"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "slirp-1.0.16/src/ppp/chap.c" of archive slirp-1.0.16.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 /*
    2  * chap.c - Cryptographic Handshake Authentication Protocol.
    3  *
    4  * Copyright (c) 1991 Gregory M. Christy.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms are permitted
    8  * provided that the above copyright notice and this paragraph are
    9  * duplicated in all such forms and that any documentation,
   10  * advertising materials, and other materials related to such
   11  * distribution and use acknowledge that the software was developed
   12  * by Gregory M. Christy.  The name of the author may not be used to
   13  * endorse or promote products derived from this software without
   14  * specific prior written permission.
   15  *
   16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
   18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   19  */
   20 
   21 #ifndef lint
   22 static char rcsid[] = "$Id: chap.c,v 1.7 1995/04/24 05:59:12 paulus Exp $";
   23 #endif
   24 
   25 /*
   26  * TODO:
   27  */
   28 
   29 #include <stdio.h>
   30 #include <string.h>
   31 #include <sys/types.h>
   32 #include <sys/time.h>
   33 #include <syslog.h>
   34 
   35 #include "pppd.h"
   36 #include "chap.h"
   37 #include "md5.h"
   38 
   39 chap_state chap[NUM_PPP];		/* CHAP state; one for each unit */
   40 
   41 static void ChapChallengeTimeout __P((caddr_t));
   42 static void ChapResponseTimeout __P((caddr_t));
   43 static void ChapReceiveChallenge __P((chap_state *, u_char *, int, int));
   44 static void ChapReceiveResponse __P((chap_state *, u_char *, int, int));
   45 static void ChapReceiveSuccess __P((chap_state *, u_char *, int, int));
   46 static void ChapReceiveFailure __P((chap_state *, u_char *, int, int));
   47 static void ChapSendStatus __P((chap_state *, int));
   48 static void ChapSendChallenge __P((chap_state *));
   49 static void ChapSendResponse __P((chap_state *));
   50 static void ChapGenChallenge __P((chap_state *));
   51 
   52 extern double drand48 __P((void));
   53 extern void srand48 __P((long));
   54 
   55 /*
   56  * ChapInit - Initialize a CHAP unit.
   57  */
   58 void
   59 ChapInit(unit)
   60     int unit;
   61 {
   62     chap_state *cstate = &chap[unit];
   63 
   64     BZERO(cstate, sizeof(*cstate));
   65     cstate->unit = unit;
   66     cstate->clientstate = CHAPCS_INITIAL;
   67     cstate->serverstate = CHAPSS_INITIAL;
   68     cstate->timeouttime = CHAP_DEFTIMEOUT;
   69     cstate->max_transmits = CHAP_DEFTRANSMITS;
   70     /* random number generator is initialized in magic_init */
   71 }
   72 
   73 
   74 /*
   75  * ChapAuthWithPeer - Authenticate us with our peer (start client).
   76  *
   77  */
   78 void
   79 ChapAuthWithPeer(unit, our_name, digest)
   80     int unit;
   81     char *our_name;
   82     int digest;
   83 {
   84     chap_state *cstate = &chap[unit];
   85 
   86     cstate->resp_name = our_name;
   87     cstate->resp_type = digest;
   88 
   89     if (cstate->clientstate == CHAPCS_INITIAL ||
   90 	cstate->clientstate == CHAPCS_PENDING) {
   91 	/* lower layer isn't up - wait until later */
   92 	cstate->clientstate = CHAPCS_PENDING;
   93 	return;
   94     }
   95 
   96     /*
   97      * We get here as a result of LCP coming up.
   98      * So even if CHAP was open before, we will
   99      * have to re-authenticate ourselves.
  100      */
  101     cstate->clientstate = CHAPCS_LISTEN;
  102 }
  103 
  104 
  105 /*
  106  * ChapAuthPeer - Authenticate our peer (start server).
  107  */
  108 void
  109 ChapAuthPeer(unit, our_name, digest)
  110     int unit;
  111     char *our_name;
  112     int digest;
  113 {
  114     chap_state *cstate = &chap[unit];
  115 
  116     cstate->chal_name = our_name;
  117     cstate->chal_type = digest;
  118 
  119     if (cstate->serverstate == CHAPSS_INITIAL ||
  120 	cstate->serverstate == CHAPSS_PENDING) {
  121 	/* lower layer isn't up - wait until later */
  122 	cstate->serverstate = CHAPSS_PENDING;
  123 	return;
  124     }
  125 
  126     ChapGenChallenge(cstate);
  127     ChapSendChallenge(cstate);		/* crank it up dude! */
  128     cstate->serverstate = CHAPSS_INITIAL_CHAL;
  129 }
  130 
  131 
  132 /*
  133  * ChapChallengeTimeout - Timeout expired on sending challenge.
  134  */
  135 static void
  136 ChapChallengeTimeout(arg)
  137     caddr_t arg;
  138 {
  139     chap_state *cstate = (chap_state *) arg;
  140 
  141     /* if we aren't sending challenges, don't worry.  then again we */
  142     /* probably shouldn't be here either */
  143     if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
  144 	cstate->serverstate != CHAPSS_RECHALLENGE)
  145 	return;
  146 
  147     if (cstate->chal_transmits >= cstate->max_transmits) {
  148 	/* give up on peer */
  149 	do_syslog(LOG_ERR, "Peer failed to respond to CHAP challenge");
  150 	cstate->serverstate = CHAPSS_BADAUTH;
  151 	auth_peer_fail(cstate->unit, PPP_CHAP);
  152 	return;
  153     }
  154 
  155     ChapSendChallenge(cstate);		/* Re-send challenge */
  156 }
  157 
  158 
  159 /*
  160  * ChapResponseTimeout - Timeout expired on sending response.
  161  */
  162 static void
  163 ChapResponseTimeout(arg)
  164     caddr_t arg;
  165 {
  166     chap_state *cstate = (chap_state *) arg;
  167 
  168     /* if we aren't sending a response, don't worry. */
  169     if (cstate->clientstate != CHAPCS_RESPONSE)
  170 	return;
  171 
  172     ChapSendResponse(cstate);		/* re-send response */
  173 }
  174 
  175 
  176 /*
  177  * ChapRechallenge - Time to challenge the peer again.
  178  */
  179 static void
  180 ChapRechallenge(arg)
  181     caddr_t arg;
  182 {
  183     chap_state *cstate = (chap_state *) arg;
  184 
  185     /* if we aren't sending a response, don't worry. */
  186     if (cstate->serverstate != CHAPSS_OPEN)
  187 	return;
  188 
  189     ChapGenChallenge(cstate);
  190     ChapSendChallenge(cstate);
  191     cstate->serverstate = CHAPSS_RECHALLENGE;
  192 }
  193 
  194 
  195 /*
  196  * ChapLowerUp - The lower layer is up.
  197  *
  198  * Start up if we have pending requests.
  199  */
  200 void
  201 ChapLowerUp(unit)
  202     int unit;
  203 {
  204     chap_state *cstate = &chap[unit];
  205 
  206     if (cstate->clientstate == CHAPCS_INITIAL)
  207 	cstate->clientstate = CHAPCS_CLOSED;
  208     else if (cstate->clientstate == CHAPCS_PENDING)
  209 	cstate->clientstate = CHAPCS_LISTEN;
  210 
  211     if (cstate->serverstate == CHAPSS_INITIAL)
  212 	cstate->serverstate = CHAPSS_CLOSED;
  213     else if (cstate->serverstate == CHAPSS_PENDING) {
  214 	ChapGenChallenge(cstate);
  215 	ChapSendChallenge(cstate);
  216 	cstate->serverstate = CHAPSS_INITIAL_CHAL;
  217     }
  218 }
  219 
  220 
  221 /*
  222  * ChapLowerDown - The lower layer is down.
  223  *
  224  * Cancel all timeouts.
  225  */
  226 void
  227 ChapLowerDown(unit)
  228     int unit;
  229 {
  230     chap_state *cstate = &chap[unit];
  231 
  232     /* Timeout(s) pending?  Cancel if so. */
  233     if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
  234 	cstate->serverstate == CHAPSS_RECHALLENGE)
  235 	UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate);
  236     else if (cstate->serverstate == CHAPSS_OPEN
  237 	     && cstate->chal_interval != 0)
  238 	UNTIMEOUT(ChapRechallenge, (caddr_t) cstate);
  239     if (cstate->clientstate == CHAPCS_RESPONSE)
  240 	UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
  241 
  242     cstate->clientstate = CHAPCS_INITIAL;
  243     cstate->serverstate = CHAPSS_INITIAL;
  244 }
  245 
  246 
  247 /*
  248  * ChapProtocolReject - Peer doesn't grok CHAP.
  249  */
  250 void
  251 ChapProtocolReject(unit)
  252     int unit;
  253 {
  254     chap_state *cstate = &chap[unit];
  255 
  256     if (cstate->serverstate != CHAPSS_INITIAL &&
  257 	cstate->serverstate != CHAPSS_CLOSED)
  258 	auth_peer_fail(unit, PPP_CHAP);
  259     if (cstate->clientstate != CHAPCS_INITIAL &&
  260 	cstate->clientstate != CHAPCS_CLOSED)
  261 	auth_withpeer_fail(unit, PPP_CHAP);
  262     ChapLowerDown(unit);		/* shutdown chap */
  263 }
  264 
  265 
  266 /*
  267  * ChapInput - Input CHAP packet.
  268  */
  269 void
  270 ChapInput(unit, inpacket, packet_len)
  271     int unit;
  272     u_char *inpacket;
  273     int packet_len;
  274 {
  275     chap_state *cstate = &chap[unit];
  276     u_char *inp;
  277     u_char code, id;
  278     int len;
  279 
  280     /*
  281      * Parse header (code, id and length).
  282      * If packet too short, drop it.
  283      */
  284     inp = inpacket;
  285     if (packet_len < CHAP_HEADERLEN) {
  286 	CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header."));
  287 	return;
  288     }
  289     GETCHAR(code, inp);
  290     GETCHAR(id, inp);
  291     GETSHORT(len, inp);
  292     if (len < CHAP_HEADERLEN) {
  293 	CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length."));
  294 	return;
  295     }
  296     if (len > packet_len) {
  297 	CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet."));
  298 	return;
  299     }
  300     len -= CHAP_HEADERLEN;
  301 
  302     /*
  303      * Action depends on code (as in fact it usually does :-).
  304      */
  305     switch (code) {
  306     case CHAP_CHALLENGE:
  307 	ChapReceiveChallenge(cstate, inp, id, len);
  308 	break;
  309 
  310     case CHAP_RESPONSE:
  311 	ChapReceiveResponse(cstate, inp, id, len);
  312 	break;
  313 
  314     case CHAP_FAILURE:
  315 	ChapReceiveFailure(cstate, inp, id, len);
  316 	break;
  317 
  318     case CHAP_SUCCESS:
  319 	ChapReceiveSuccess(cstate, inp, id, len);
  320 	break;
  321 
  322     default:				/* Need code reject? */
  323 	do_syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code);
  324 	break;
  325     }
  326 }
  327 
  328 
  329 /*
  330  * ChapReceiveChallenge - Receive Challenge and send Response.
  331  */
  332 static void
  333 ChapReceiveChallenge(cstate, inp, id, len)
  334     chap_state *cstate;
  335     u_char *inp;
  336     int id;
  337     int len;
  338 {
  339     int rchallenge_len;
  340     u_char *rchallenge;
  341     int secret_len;
  342     char secret[MAXSECRETLEN];
  343     char rhostname[256];
  344     MD5_CTX mdContext;
  345 
  346     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id));
  347     if (cstate->clientstate == CHAPCS_CLOSED ||
  348 	cstate->clientstate == CHAPCS_PENDING) {
  349 	CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d",
  350 		   cstate->clientstate));
  351 	return;
  352     }
  353 
  354     if (len < 2) {
  355 	CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
  356 	return;
  357     }
  358 
  359     GETCHAR(rchallenge_len, inp);
  360     len -= sizeof (u_char) + rchallenge_len;	/* now name field length */
  361     if (len < 0) {
  362 	CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
  363 	return;
  364     }
  365     rchallenge = inp;
  366     INCPTR(rchallenge_len, inp);
  367 
  368     if (len >= sizeof(rhostname))
  369 	len = sizeof(rhostname) - 1;
  370     BCOPY(inp, rhostname, len);
  371     rhostname[len] = '\000';
  372 
  373     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field: %s",
  374 	       rhostname));
  375 
  376     /* get secret for authenticating ourselves with the specified host */
  377     if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
  378 		    secret, &secret_len, 0)) {
  379 	secret_len = 0;		/* assume null secret if can't find one */
  380 	do_syslog(LOG_WARNING, "No CHAP secret found for authenticating us to %s",
  381 	       rhostname);
  382     }
  383 
  384     /* cancel response send timeout if necessary */
  385     if (cstate->clientstate == CHAPCS_RESPONSE)
  386 	UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
  387 
  388     cstate->resp_id = id;
  389     cstate->resp_transmits = 0;
  390 
  391     /*  generate MD based on negotiated type */
  392     switch (cstate->resp_type) {
  393 
  394     case CHAP_DIGEST_MD5:		/* only MD5 is defined for now */
  395 	MD5Init(&mdContext);
  396 	MD5Update(&mdContext, &cstate->resp_id, 1);
  397 	MD5Update(&mdContext, secret, secret_len);
  398 	MD5Update(&mdContext, rchallenge, rchallenge_len);
  399 	MD5Final(&mdContext);
  400 	BCOPY(mdContext.digest, cstate->response, MD5_SIGNATURE_SIZE);
  401 	cstate->resp_length = MD5_SIGNATURE_SIZE;
  402 	break;
  403 
  404     default:
  405 	CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type));
  406 	return;
  407     }
  408 
  409     ChapSendResponse(cstate);
  410 }
  411 
  412 
  413 /*
  414  * ChapReceiveResponse - Receive and process response.
  415  */
  416 static void
  417 ChapReceiveResponse(cstate, inp, id, len)
  418     chap_state *cstate;
  419     u_char *inp;
  420     int id;
  421     int len;
  422 {
  423     u_char *remmd, remmd_len;
  424     int secret_len, old_state;
  425     int code;
  426     char rhostname[256];
  427     u_char buf[256];
  428     MD5_CTX mdContext;
  429     u_char msg[256];
  430     char secret[MAXSECRETLEN];
  431 
  432     CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id));
  433 
  434     if (cstate->serverstate == CHAPSS_CLOSED ||
  435 	cstate->serverstate == CHAPSS_PENDING) {
  436 	CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d",
  437 		   cstate->serverstate));
  438 	return;
  439     }
  440 
  441     if (id != cstate->chal_id)
  442 	return;			/* doesn't match ID of last challenge */
  443 
  444     /*
  445      * If we have received a duplicate or bogus Response,
  446      * we have to send the same answer (Success/Failure)
  447      * as we did for the first Response we saw.
  448      */
  449     if (cstate->serverstate == CHAPSS_OPEN) {
  450 	ChapSendStatus(cstate, CHAP_SUCCESS);
  451 	return;
  452     }
  453     if (cstate->serverstate == CHAPSS_BADAUTH) {
  454 	ChapSendStatus(cstate, CHAP_FAILURE);
  455 	return;
  456     }
  457 
  458     if (len < 2) {
  459 	CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
  460 	return;
  461     }
  462     GETCHAR(remmd_len, inp);		/* get length of MD */
  463     remmd = inp;			/* get pointer to MD */
  464     INCPTR(remmd_len, inp);
  465 
  466     len -= sizeof (u_char) + remmd_len;
  467     if (len < 0) {
  468 	CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
  469 	return;
  470     }
  471 
  472     UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate);
  473 
  474     if (len >= sizeof(rhostname))
  475 	len = sizeof(rhostname) - 1;
  476     BCOPY(inp, rhostname, len);
  477     rhostname[len] = '\000';
  478 
  479     CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s",
  480 	       rhostname));
  481 
  482     /*
  483      * Get secret for authenticating them with us,
  484      * do the hash ourselves, and compare the result.
  485      */
  486     code = CHAP_FAILURE;
  487     if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
  488 		   secret, &secret_len, 1)) {
  489 	do_syslog(LOG_WARNING, "No CHAP secret found for authenticating %s",
  490 	       rhostname);
  491     } else {
  492 
  493 	/*  generate MD based on negotiated type */
  494 	switch (cstate->chal_type) {
  495 
  496 	case CHAP_DIGEST_MD5:		/* only MD5 is defined for now */
  497 	    if (remmd_len != MD5_SIGNATURE_SIZE)
  498 		break;			/* it's not even the right length */
  499 	    MD5Init(&mdContext);
  500 	    MD5Update(&mdContext, &cstate->chal_id, 1);
  501 	    MD5Update(&mdContext, secret, secret_len);
  502 	    MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
  503 	    MD5Final(&mdContext);
  504 
  505 	    /* compare local and remote MDs and send the appropriate status */
  506 	    if (memcmp (mdContext.digest, remmd, MD5_SIGNATURE_SIZE) == 0)
  507 		code = CHAP_SUCCESS;	/* they are the same! */
  508 	    break;
  509 
  510 	default:
  511 	    CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->chal_type));
  512 	}
  513     }
  514 
  515     ChapSendStatus(cstate, code);
  516 
  517     if (code == CHAP_SUCCESS) {
  518 	old_state = cstate->serverstate;
  519 	cstate->serverstate = CHAPSS_OPEN;
  520 	if (old_state == CHAPSS_INITIAL_CHAL) {
  521 	    auth_peer_success(cstate->unit, PPP_CHAP);
  522 	}
  523 	if (cstate->chal_interval != 0)
  524 	    TIMEOUT(ChapRechallenge, (caddr_t) cstate, cstate->chal_interval);
  525 
  526     } else {
  527 	do_syslog(LOG_ERR, "CHAP peer authentication failed");
  528 	cstate->serverstate = CHAPSS_BADAUTH;
  529 	auth_peer_fail(cstate->unit, PPP_CHAP);
  530     }
  531 }
  532 
  533 /*
  534  * ChapReceiveSuccess - Receive Success
  535  */
  536 static void
  537 ChapReceiveSuccess(cstate, inp, id, len)
  538     chap_state *cstate;
  539     u_char *inp;
  540     u_char id;
  541     int len;
  542 {
  543 
  544     CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id));
  545 
  546     if (cstate->clientstate == CHAPCS_OPEN)
  547 	/* presumably an answer to a duplicate response */
  548 	return;
  549 
  550     if (cstate->clientstate != CHAPCS_RESPONSE) {
  551 	/* don't know what this is */
  552 	CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n",
  553 		   cstate->clientstate));
  554 	return;
  555     }
  556 
  557     UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
  558 
  559     /*
  560      * Print message.
  561      */
  562     if (len > 0)
  563 	PRINTMSG(inp, len);
  564 
  565     cstate->clientstate = CHAPCS_OPEN;
  566 
  567     auth_withpeer_success(cstate->unit, PPP_CHAP);
  568 }
  569 
  570 
  571 /*
  572  * ChapReceiveFailure - Receive failure.
  573  */
  574 static void
  575 ChapReceiveFailure(cstate, inp, id, len)
  576     chap_state *cstate;
  577     u_char *inp;
  578     u_char id;
  579     int len;
  580 {
  581     u_char msglen;
  582     u_char *msg;
  583 
  584     CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id));
  585 
  586     if (cstate->clientstate != CHAPCS_RESPONSE) {
  587 	/* don't know what this is */
  588 	CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n",
  589 		   cstate->clientstate));
  590 	return;
  591     }
  592 
  593     UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
  594 
  595     /*
  596      * Print message.
  597      */
  598     if (len > 0)
  599 	PRINTMSG(inp, len);
  600 
  601     do_syslog(LOG_ERR, "CHAP authentication failed");
  602     auth_withpeer_fail(cstate->unit, PPP_CHAP);
  603 }
  604 
  605 
  606 /*
  607  * ChapSendChallenge - Send an Authenticate challenge.
  608  */
  609 static void
  610 ChapSendChallenge(cstate)
  611     chap_state *cstate;
  612 {
  613     u_char *outp;
  614     int chal_len, name_len;
  615     int outlen;
  616 
  617     chal_len = cstate->chal_len;
  618     name_len = strlen(cstate->chal_name);
  619     outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
  620     outp = outpacket_buf;
  621 
  622     MAKEHEADER(outp, PPP_CHAP);		/* paste in a CHAP header */
  623 
  624     PUTCHAR(CHAP_CHALLENGE, outp);
  625     PUTCHAR(cstate->chal_id, outp);
  626     PUTSHORT(outlen, outp);
  627 
  628     PUTCHAR(chal_len, outp);		/* put length of challenge */
  629     BCOPY(cstate->challenge, outp, chal_len);
  630     INCPTR(chal_len, outp);
  631 
  632     BCOPY(cstate->chal_name, outp, name_len);	/* append hostname */
  633 
  634     output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
  635 
  636     CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->chal_id));
  637 
  638     TIMEOUT(ChapChallengeTimeout, (caddr_t) cstate, cstate->timeouttime);
  639     ++cstate->chal_transmits;
  640 }
  641 
  642 
  643 /*
  644  * ChapSendStatus - Send a status response (ack or nak).
  645  */
  646 static void
  647 ChapSendStatus(cstate, code)
  648     chap_state *cstate;
  649     int code;
  650 {
  651     u_char *outp;
  652     int outlen, msglen;
  653     char msg[256];
  654 
  655     if (code == CHAP_SUCCESS)
  656 	snprintf(msg, sizeof(msg), "Welcome to %s.", hostname);
  657     else
  658 	sprintf(msg, "I don't like you.  Go 'way.");
  659     msglen = strlen(msg);
  660 
  661     outlen = CHAP_HEADERLEN + msglen;
  662     outp = outpacket_buf;
  663 
  664     MAKEHEADER(outp, PPP_CHAP);	/* paste in a header */
  665 
  666     PUTCHAR(code, outp);
  667     PUTCHAR(cstate->chal_id, outp);
  668     PUTSHORT(outlen, outp);
  669     BCOPY(msg, outp, msglen);
  670     output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
  671 
  672     CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code,
  673 	       cstate->chal_id));
  674 }
  675 
  676 /*
  677  * ChapGenChallenge is used to generate a pseudo-random challenge string of
  678  * a pseudo-random length between min_len and max_len.  The challenge
  679  * string and its length are stored in *cstate, and various other fields of
  680  * *cstate are initialized.
  681  */
  682 
  683 static void
  684 ChapGenChallenge(cstate)
  685     chap_state *cstate;
  686 {
  687     int chal_len;
  688     u_char *ptr = cstate->challenge;
  689     unsigned int i;
  690 
  691     /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
  692        MAX_CHALLENGE_LENGTH */
  693     chal_len =  (unsigned) ((drand48() *
  694 			     (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
  695 			    MIN_CHALLENGE_LENGTH);
  696     cstate->chal_len = chal_len;
  697     cstate->chal_id = ++cstate->id;
  698     cstate->chal_transmits = 0;
  699 
  700     /* generate a random string */
  701     for (i = 0; i < chal_len; i++ )
  702 	*ptr++ = (char) (drand48() * 0xff);
  703 }
  704 
  705 /*
  706  * ChapSendResponse - send a response packet with values as specified
  707  * in *cstate.
  708  */
  709 /* ARGSUSED */
  710 static void
  711 ChapSendResponse(cstate)
  712     chap_state *cstate;
  713 {
  714     u_char *outp;
  715     int outlen, md_len, name_len;
  716 
  717     md_len = cstate->resp_length;
  718     name_len = strlen(cstate->resp_name);
  719     outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
  720     outp = outpacket_buf;
  721 
  722     MAKEHEADER(outp, PPP_CHAP);
  723 
  724     PUTCHAR(CHAP_RESPONSE, outp);	/* we are a response */
  725     PUTCHAR(cstate->resp_id, outp);	/* copy id from challenge packet */
  726     PUTSHORT(outlen, outp);		/* packet length */
  727 
  728     PUTCHAR(md_len, outp);		/* length of MD */
  729     BCOPY(cstate->response, outp, md_len);	/* copy MD to buffer */
  730     INCPTR(md_len, outp);
  731 
  732     BCOPY(cstate->resp_name, outp, name_len); /* append our name */
  733 
  734     /* send the packet */
  735     output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
  736 
  737     cstate->clientstate = CHAPCS_RESPONSE;
  738     TIMEOUT(ChapResponseTimeout, (caddr_t) cstate, cstate->timeouttime);
  739     ++cstate->resp_transmits;
  740 }
  741 
  742 /*
  743  * ChapPrintPkt - print the contents of a CHAP packet.
  744  */
  745 char *ChapCodenames[] = {
  746     "Challenge", "Response", "Success", "Failure"
  747 };
  748 
  749 int
  750 ChapPrintPkt(p, plen, printer, arg)
  751     u_char *p;
  752     int plen;
  753     void (*printer) __P((void *, char *, ...));
  754     void *arg;
  755 {
  756     int code, id, len;
  757     int clen, nlen;
  758     u_char x;
  759 
  760     if (plen < CHAP_HEADERLEN)
  761 	return 0;
  762     GETCHAR(code, p);
  763     GETCHAR(id, p);
  764     GETSHORT(len, p);
  765     if (len < CHAP_HEADERLEN || len > plen)
  766 	return 0;
  767 
  768     if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
  769 	printer(arg, " %s", ChapCodenames[code-1]);
  770     else
  771 	printer(arg, " code=0x%x", code);
  772     printer(arg, " id=0x%x", id);
  773     len -= CHAP_HEADERLEN;
  774     switch (code) {
  775     case CHAP_CHALLENGE:
  776     case CHAP_RESPONSE:
  777 	if (len < 1)
  778 	    break;
  779 	clen = p[0];
  780 	if (len < clen + 1)
  781 	    break;
  782 	++p;
  783 	nlen = len - clen - 1;
  784 	printer(arg, " <");
  785 	for (; clen > 0; --clen) {
  786 	    GETCHAR(x, p);
  787 	    printer(arg, "%.2x", x);
  788 	}
  789 	printer(arg, ">, name = ");
  790 	print_string((char *)p, nlen, printer, arg);
  791 	break;
  792     case CHAP_FAILURE:
  793     case CHAP_SUCCESS:
  794 	printer(arg, " ");
  795 	print_string((char *)p, len, printer, arg);
  796 	break;
  797     default:
  798 	for (clen = len; clen > 0; --clen) {
  799 	    GETCHAR(x, p);
  800 	    printer(arg, " %.2x", x);
  801 	}
  802     }
  803 
  804     return len + CHAP_HEADERLEN;
  805 }