home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / SUN / PPP / SUNOS_OL / PPPD_1_0.TAR / chap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-01-14  |  16.2 KB  |  662 lines

  1. /*
  2.  * chap.c - Crytographic 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. /*
  22.  * TODO:
  23.  */
  24.  
  25. #include <stdio.h>
  26. #include <sys/types.h>
  27. #include <sys/time.h>
  28. #include <syslog.h>
  29.  
  30. #ifdef STREAMS
  31. #include <sys/socket.h>
  32. #include <net/if.h>
  33. #include <sys/stream.h>
  34. #endif
  35.  
  36. #include "ppp.h"
  37. #include "fsm.h"
  38. #include "lcp.h"
  39. #include "chap.h"
  40. #include "upap.h"
  41. #include "ipcp.h"
  42. #include "md5.h"
  43.  
  44. chap_state chap[NPPP];        /* CHAP state; one for each unit */
  45.  
  46. static void ChapTimeout __ARGS((caddr_t));
  47. static void ChapReceiveChallenge __ARGS((chap_state *, u_char *, u_char, int));
  48. static void ChapReceiveResponse __ARGS((chap_state *, u_char *, u_char, int));
  49. static void ChapReceiveSuccess __ARGS((chap_state *, u_char *, u_char, int));
  50. static void ChapReceiveFailure __ARGS((chap_state *, u_char *, u_char, int));
  51. static void ChapSendStatus __ARGS((chap_state *, u_char, u_char,
  52.                    u_char *, int));
  53. static void ChapSendChallenge __ARGS((chap_state *));
  54. static void ChapSendResponse __ARGS((chap_state *, u_char, u_char *, int));
  55. static void ChapGenChallenge __ARGS((u_char, u_char *));
  56.  
  57. extern double drand48 __ARGS((void));
  58.  
  59. /*
  60.  * ChapInit - Initialize a CHAP unit.
  61.  */
  62. void
  63.   ChapInit(unit)
  64. int unit;
  65. {
  66.   chap_state *cstate = &chap[unit];
  67.  
  68.   cstate->unit = unit;
  69.   cstate->chal_str[0] = '\000';
  70.   cstate->chal_len = 0;
  71.   cstate->clientstate = CHAPCS_CLOSED;
  72.   cstate->serverstate = CHAPSS_CLOSED;
  73.   cstate->flags = 0;
  74.   cstate->id = 0;
  75.   cstate->timeouttime = CHAP_DEFTIMEOUT;
  76.   cstate->retransmits = 0;
  77.   srand48((long) time(NULL));    /* joggle random number generator */
  78. }
  79.  
  80.  
  81. /*
  82.  * ChapAuthWithPeer - Authenticate us with our peer (start client).
  83.  *
  84.  */
  85. void
  86.   ChapAuthWithPeer(unit)
  87. int unit;
  88. {
  89.   chap_state *cstate = &chap[unit];
  90.   
  91.   cstate->flags &= ~CHAPF_AWPPENDING;    /* Clear pending flag */
  92.   
  93.   /* Protect against programming errors that compromise security */
  94.   if (cstate->serverstate != CHAPSS_CLOSED ||
  95.       cstate->flags & CHAPF_APPENDING) {
  96.     CHAPDEBUG((LOG_INFO,
  97.            "ChapAuthWithPeer: we were called already!"))
  98.     return;
  99.   }
  100.   
  101.   if (cstate->clientstate == CHAPCS_CHALLENGE_SENT ||  /* should we be here? */
  102.       cstate->clientstate == CHAPCS_OPEN)
  103.     return;
  104.   
  105.   /* Lower layer up? */
  106.   if (!(cstate->flags & CHAPF_LOWERUP)) {
  107.     cstate->flags |= CHAPF_AWPPENDING; /* Nah, Wait */
  108.     return;
  109.   }
  110.   ChapSendChallenge(cstate);        /* crank it up dude! */
  111.   TIMEOUT(ChapTimeout, (caddr_t) cstate, cstate->timeouttime); 
  112.                     /* set-up timeout */
  113.   cstate->clientstate = CHAPCS_CHALLENGE_SENT; /* update state */
  114.   cstate->retransmits = 0;
  115. }
  116.  
  117.  
  118. /*
  119.  * ChapAuthPeer - Authenticate our peer (start server).
  120.  */
  121. void
  122.   ChapAuthPeer(unit)
  123. int unit;
  124. {
  125.   chap_state *cstate = &chap[unit];
  126.   
  127.   cstate->flags &= ~CHAPF_APPENDING;    /* Clear pending flag */
  128.   
  129.   /* Already authenticat{ed,ing}? */
  130.   if (cstate->serverstate == CHAPSS_LISTEN ||
  131.       cstate->serverstate == CHAPSS_OPEN)
  132.     return;
  133.   
  134.   /* Lower layer up? */
  135.   if (!(cstate->flags & CHAPF_LOWERUP)) {
  136.     cstate->flags |= CHAPF_APPENDING;    /* Wait for desired event */
  137.     return;
  138.   }
  139.   cstate->serverstate = CHAPSS_LISTEN;
  140. }
  141.  
  142.  
  143. /*
  144.  * ChapTimeout - Timeout expired.
  145.  */
  146. static void
  147.   ChapTimeout(arg)
  148. caddr_t arg;
  149. {
  150.   chap_state *cstate = (chap_state *) arg;
  151.   
  152.   /* if we aren't sending challenges, don't worry.  then again we */
  153.   /* probably shouldn't be here either */
  154.   if (cstate->clientstate != CHAPCS_CHALLENGE_SENT)
  155.     return;
  156.   
  157.   ChapSendChallenge(cstate);            /* Send challenge */
  158.   TIMEOUT(ChapTimeout, (caddr_t) cstate, cstate->timeouttime);
  159.   ++cstate->retransmits;
  160. }
  161.  
  162.  
  163. /*
  164.  * ChapLowerUp - The lower layer is up.
  165.  *
  166.  * Start up if we have pending requests.
  167.  */
  168. void
  169.   ChapLowerUp(unit)
  170. int unit;
  171. {
  172.   chap_state *cstate = &chap[unit];
  173.   
  174.   cstate->flags |= CHAPF_LOWERUP;
  175.   if (cstate->flags & CHAPF_AWPPENDING)    /* were we attempting authwithpeer? */
  176.     ChapAuthWithPeer(unit);    /* Try it now */
  177.   if (cstate->flags & CHAPF_APPENDING)    /* or authpeer? */
  178.     ChapAuthPeer(unit);
  179. }
  180.  
  181.  
  182. /*
  183.  * ChapLowerDown - The lower layer is down.
  184.  *
  185.  * Cancel all timeouts.
  186.  */
  187. void
  188.   ChapLowerDown(unit)
  189. int unit;
  190. {
  191.   chap_state *cstate = &chap[unit];
  192.   
  193.   cstate->flags &= ~CHAPF_LOWERUP;
  194.   
  195.   if (cstate->clientstate == CHAPCS_CHALLENGE_SENT) /* Timeout pending? */
  196.     UNTIMEOUT(ChapTimeout, (caddr_t) cstate);    /* Cancel timeout */
  197.   
  198.   if (cstate->serverstate == CHAPSS_OPEN) /* have we successfully authed? */
  199.     LOGOUT(unit);
  200.   cstate->clientstate = CHAPCS_CLOSED;
  201.   cstate->serverstate = CHAPSS_CLOSED;
  202. }
  203.  
  204.  
  205. /*
  206.  * ChapProtocolReject - Peer doesn't grok CHAP.
  207.  */
  208. void
  209.   ChapProtocolReject(unit)
  210. int unit;
  211. {
  212.   ChapLowerDown(unit);        /* shutdown chap */
  213.  
  214.  
  215. /* Note: should we bail here if chap is required? */
  216. }
  217.  
  218.  
  219. /*
  220.  * ChapInput - Input CHAP packet.
  221.  */
  222. void
  223.   ChapInput(unit, inpacket, packet_len)
  224. int unit;
  225. u_char *inpacket;
  226. int packet_len;
  227. {
  228.   chap_state *cstate = &chap[unit];
  229.   u_char *inp;
  230.   u_char code, id;
  231.   int len;
  232.   
  233.   /*
  234.    * Parse header (code, id and length).
  235.    * If packet too short, drop it.
  236.    */
  237.   inp = inpacket;
  238.   if (packet_len < CHAP_HEADERLEN) {
  239.     CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header."))
  240.     return;
  241.   }
  242.   GETCHAR(code, inp);
  243.   GETCHAR(id, inp);
  244.   GETSHORT(len, inp);
  245.   if (len < CHAP_HEADERLEN) {
  246.     CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length."))
  247.     return;
  248.   }
  249.   if (len > packet_len) {
  250.     CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet."))
  251.     return;
  252.   }
  253.   len -= CHAP_HEADERLEN;
  254.   
  255.   /*
  256.    * Action depends on code.
  257.    */
  258.   switch (code) {
  259.   case CHAP_CHALLENGE:
  260.     ChapReceiveChallenge(cstate, inp, id, len);
  261.     break;
  262.     
  263.   case CHAP_RESPONSE:
  264.     ChapReceiveResponse(cstate, inp, id, len);
  265.     break;
  266.     
  267.   case CHAP_FAILURE:
  268.     ChapReceiveFailure(cstate, inp, id, len);
  269.     break;
  270.  
  271.   case CHAP_SUCCESS:
  272.     ChapReceiveSuccess(cstate, inp, id, len);
  273.     break;
  274.  
  275.   default:                /* Need code reject? */
  276.     syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code);
  277.     break;
  278.   }
  279. }
  280.  
  281.  
  282. /*
  283.  * ChapReceiveChallenge - Receive Challenge.
  284.  */
  285. static void
  286.   ChapReceiveChallenge(cstate, inp, id, len)
  287. chap_state *cstate;
  288. u_char *inp;
  289. u_char id;
  290. int len;
  291. {
  292.   u_char rchallenge_len;
  293.   u_char *rchallenge;
  294.   u_char secret[MAX_SECRET_LEN];
  295.   int secret_len;
  296.   u_char rhostname[256];
  297.   u_char buf[256];
  298.   MD5_CTX mdContext;
  299.  
  300.   CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id))
  301.   if (cstate->serverstate != CHAPSS_LISTEN) {
  302.     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received challenge but not in listen state"))
  303.     return;
  304.   }
  305.   
  306.   if (len < 2) {
  307.     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."))
  308.     return;
  309.   }
  310.   GETCHAR(rchallenge_len, inp);
  311.   len -= sizeof (u_char) + rchallenge_len ;
  312.   if (len < 0) {
  313.     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."))
  314.     return;
  315.   }
  316.   rchallenge = inp;
  317.   INCPTR(rchallenge_len, inp);
  318.  
  319.   BCOPY(inp, rhostname, len);
  320.   rhostname[len] = '\000';
  321.  
  322.   CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field: %s",
  323.          rhostname))
  324.   GETSECRET(rhostname, secret, &secret_len);/* get secret for specified host */
  325.  
  326.   BCOPY(rchallenge, buf, rchallenge_len); /* copy challenge into buffer */
  327.   BCOPY(secret, buf + rchallenge_len, secret_len); /* append secret */
  328.  
  329.   /*  generate MD based on negotiated type */
  330.  
  331.   switch (lcp_hisoptions[cstate->unit].chap_mdtype) { 
  332.  
  333.   case CHAP_DIGEST_MD5:        /* only MD5 is defined for now */
  334.     MD5Init(&mdContext);
  335.     MD5Update(&mdContext, buf, rchallenge_len + secret_len);
  336.     MD5Final(&mdContext); 
  337.     ChapSendResponse(cstate, id, &mdContext.digest[0], MD5_SIGNATURE_SIZE);
  338.     break;
  339.  
  340.   default:
  341.     CHAPDEBUG((LOG_INFO, "unknown digest type %d",
  342.            lcp_hisoptions[cstate->unit].chap_mdtype))
  343.   }
  344.  
  345. }
  346.  
  347.  
  348. /*
  349.  * ChapReceiveResponse - Receive and process response.
  350.  */
  351. static void
  352.   ChapReceiveResponse(cstate, inp, id, len)
  353. chap_state *cstate;
  354. u_char *inp;
  355. u_char id;
  356. int len;
  357. {
  358.   u_char *remmd, remmd_len;
  359.   u_char secret[MAX_SECRET_LEN];
  360.   int secret_len;
  361.   u_char chal_len = cstate->chal_len;
  362.   u_char code;
  363.   u_char rhostname[256];
  364.   u_char buf[256];
  365.   MD5_CTX mdContext;
  366.   u_char msg[256], msglen;
  367.  
  368.   CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id))
  369.  
  370. /* sanity check */
  371.   if (cstate->clientstate != CHAPCS_CHALLENGE_SENT) {
  372.     CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received response but did not send a challenge"))
  373.     return;
  374.   }
  375.   
  376.   if (len < 2) {
  377.     CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."))
  378.     return;
  379.   }
  380.   GETCHAR(remmd_len, inp);        /* get length of MD */
  381.   len -= sizeof (u_char) + remmd_len ;
  382.  
  383.   if (len < 0) {
  384.     CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."))
  385.     return;
  386.   }
  387.  
  388.   remmd = inp;            /* get pointer to MD */
  389.   INCPTR(remmd_len, inp);
  390.  
  391.   BCOPY(inp, rhostname, len);
  392.   rhostname[len] = '\000';
  393.  
  394.   CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s",
  395.          rhostname))
  396.  
  397.   GETSECRET(rhostname, secret, &secret_len);/* get secret for specified host */
  398.  
  399.   BCOPY(cstate->chal_str, buf, chal_len); /* copy challenge */
  400.                           /* into buffer */ 
  401.   BCOPY(secret, buf + chal_len, secret_len); /* append secret */
  402.  
  403.   /*  generate MD based on negotiated type */
  404.  
  405.   switch (lcp_gotoptions[cstate->unit].chap_mdtype) { 
  406.  
  407.   case CHAP_DIGEST_MD5:        /* only MD5 is defined for now */
  408.     MD5Init(&mdContext);
  409.     MD5Update(&mdContext, buf, chal_len + secret_len);
  410.     MD5Final(&mdContext); 
  411.  
  412.     /* compare local and remote MDs and send the appropriate status */
  413.  
  414.     if (bcmp (&mdContext.digest[0], remmd, MD5_SIGNATURE_SIZE)) 
  415.       code = CHAP_FAILURE;    /* they ain't the same */
  416.     else
  417.       code = CHAP_SUCCESS;    /* they are the same! */
  418.     break;
  419.  
  420.     default:
  421.       CHAPDEBUG((LOG_INFO, "unknown digest type %d",
  422.          lcp_gotoptions[cstate->unit].chap_mdtype))
  423.     }
  424.     if (code == CHAP_SUCCESS)
  425.       sprintf(msg, "Welcome to %s.", hostname);
  426.     else
  427.       sprintf(msg, "I don't like you.  Go 'way.");
  428.     msglen = strlen(msg);
  429.     ChapSendStatus(cstate, code, id, msg, msglen);
  430.   
  431.   /* only crank up IPCP when either we aren't doing PAP, or if we are, */
  432.   /* that it is in open state */
  433.  
  434.     if (code == CHAP_SUCCESS) {
  435.       cstate->serverstate = CHAPSS_OPEN;
  436.       if (!lcp_hisoptions[cstate->unit].neg_upap ||
  437.       (lcp_hisoptions[cstate->unit].neg_upap &&
  438.        upap[cstate->unit].us_serverstate == UPAPSS_OPEN ))
  439.     ipcp_activeopen(cstate->unit);    /* Start IPCP */
  440.     }
  441. }
  442. /*
  443.  * ChapReceiveSuccess - Receive Success
  444.  */
  445. /* ARGSUSED */
  446. static void
  447.   ChapReceiveSuccess(cstate, inp, id, len)
  448. chap_state *cstate;
  449. u_char *inp;
  450. u_char id;
  451. int len;
  452. {
  453.   u_char msglen;
  454.   u_char *msg;
  455.  
  456.   CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id))
  457.  
  458.   if (cstate->clientstate != CHAPCS_CHALLENGE_SENT) {
  459.     CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: received success, but did not send a challenge."))
  460.     return;
  461.   }
  462.  
  463.   /*
  464.    * Parse message.
  465.    */
  466.   if (len < sizeof (u_char)) {
  467.     CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: rcvd short packet."))
  468.     return;
  469.   }
  470.   GETCHAR(msglen, inp);
  471.   len -= sizeof (u_char);
  472.   if (len < msglen) {
  473.     CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: rcvd short packet."))
  474.     return;
  475.   }
  476.   msg = inp;
  477.   PRINTMSG(msg, msglen);
  478.   
  479.   cstate->clientstate = CHAPCS_OPEN;
  480.  
  481.   /* only crank up IPCP when either we aren't doing PAP, or if we are, */
  482.   /* that it is in open state */
  483.  
  484.   if (!lcp_gotoptions[cstate->unit].neg_chap ||
  485.       (lcp_gotoptions[cstate->unit].neg_chap &&
  486.        upap[cstate->unit].us_serverstate == UPAPCS_OPEN ))
  487.     ipcp_activeopen(cstate->unit);    /* Start IPCP */
  488. }
  489.  
  490.  
  491. /*
  492.  * ChapReceiveFailure - Receive failure.
  493.  */
  494. /* ARGSUSED */
  495. static void
  496.   ChapReceiveFailure(cstate, inp, id, len)
  497. chap_state *cstate;
  498. u_char *inp;
  499. u_char id;
  500. int len;
  501. {
  502.   u_char msglen;
  503.   u_char *msg;
  504.   
  505.   CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id))
  506.   if (cstate->clientstate != CHAPCS_CHALLENGE_SENT) /* XXX */
  507.     return;
  508.   
  509.   /*
  510.    * Parse message.
  511.    */
  512.   if (len < sizeof (u_char)) {
  513.     CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: rcvd short packet."))
  514.     return;
  515.   }
  516.   GETCHAR(msglen, inp);
  517.   len -= sizeof (u_char);
  518.   if (len < msglen) {
  519.     CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: rcvd short packet."))
  520.     return;
  521.   }
  522.   msg = inp;
  523.   PRINTMSG(msg, msglen);
  524.   
  525.   cstate->flags &= ~CHAPF_UPVALID;    /* Clear valid flag */
  526.   cstate->clientstate = CHAPCS_CLOSED;    /* Pretend for a moment */
  527.   ChapAuthWithPeer(cstate->unit);    /* Restart */
  528. }
  529.  
  530.  
  531. /*
  532.  * ChapSendChallenge - Send an Authenticate challenge.
  533.  */
  534. static void
  535.   ChapSendChallenge(cstate)
  536. chap_state *cstate;
  537. {
  538.   u_char *outp;
  539.   u_char chal_len;
  540.   int outlen;
  541.  
  542. /* pick a random challenge length between MIN_CHALLENGE_LENGTH and 
  543.    MAX_CHALLENGE_LENGTH */  
  544.   cstate->chal_len =  (unsigned) ((drand48() *
  545.                (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
  546.               MIN_CHALLENGE_LENGTH);
  547.   chal_len = cstate->chal_len;
  548.  
  549.   outlen = CHAP_HEADERLEN + 2 * sizeof (u_char) + chal_len + hostname_len;
  550.   outp = outpacket_buf;
  551.  
  552.   MAKEHEADER(outp, CHAP);        /* paste in a CHAP header */
  553.   
  554.   PUTCHAR(CHAP_CHALLENGE, outp);
  555.   PUTCHAR(++cstate->id, outp);
  556.   PUTSHORT(outlen, outp);
  557.  
  558.   PUTCHAR(chal_len, outp);    /* put length of challenge */
  559.  
  560.   ChapGenChallenge(chal_len, cstate->chal_str); /* generate a challenge string */
  561.  
  562.   BCOPY(cstate->chal_str, outp, chal_len); /* copy it the the output buffer */
  563.   INCPTR(chal_len, outp);
  564.  
  565.   BCOPY(hostname, outp, hostname_len); /* append hostname */
  566.   INCPTR(hostname_len, outp);
  567.  
  568.   output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN);
  569.   
  570.   CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->id))
  571.   cstate->clientstate |= CHAPCS_CHALLENGE_SENT;
  572. }
  573.  
  574.  
  575. /*
  576.  * ChapSendStatus - Send a status response (ack or nak).
  577.  */
  578. static void
  579.   ChapSendStatus(cstate, code, id, msg, msglen)
  580. chap_state *cstate;
  581. u_char code, id;
  582. u_char *msg;
  583. int msglen;
  584. {
  585.   u_char *outp;
  586.   int outlen;
  587.   
  588.   outlen = CHAP_HEADERLEN + msglen;
  589.   outp = outpacket_buf;
  590.  
  591.   MAKEHEADER(outp, CHAP);    /* paste in a header */
  592.   
  593.   PUTCHAR(code, outp);
  594.   PUTCHAR(id, outp);
  595.   PUTSHORT(outlen, outp);
  596.   BCOPY(msg, outp, msglen);
  597.   output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN);
  598.   
  599.   CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code, id))
  600. }
  601.  
  602. /*
  603.  * ChapGenChallenge is used to generate a pseudo-random challenge string of
  604.  * a pseudo-random length between min_len and max_len and return the
  605.  * challenge string, and the message digest of the secret appended to
  606.  * the challenge string.  the message digest type is specified by mdtype.
  607.  *
  608.  * It returns with the string in the caller-supplied buffer str (which
  609.  * should be instantiated with a length of max_len + 1), and the
  610.  * length of the generated string into chal_len.
  611.  *
  612.  */
  613.  
  614. static void
  615.   ChapGenChallenge(chal_len, str)
  616. u_char chal_len;
  617. u_char * str;
  618. {
  619.   u_char * ptr = str;
  620.   unsigned int i;
  621.  
  622.   /* generate a random string */
  623.  
  624.   for (i = 0; i < chal_len; i++ )
  625.     *ptr++ = (char) (drand48() * 0xff);
  626.       
  627.   *ptr = 0;        /* null terminate it so we can printf it */
  628. }
  629. /*
  630.  * ChapSendResponse - send a response packet with the message
  631.  *                      digest specified by md and md_len
  632.  */
  633. /* ARGSUSED */
  634. static void
  635.   ChapSendResponse(cstate, id, md, md_len)
  636. chap_state *cstate;
  637. u_char id;
  638. u_char *md;
  639. int md_len;
  640. {
  641.     u_char *outp;
  642.     int outlen;
  643.  
  644.     outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + hostname_len;
  645.     outp = outpacket_buf;
  646.     MAKEHEADER(outp, CHAP);
  647.  
  648.     PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
  649.     PUTCHAR(id, outp);        /* copy id from challenge packet */
  650.     PUTSHORT(outlen, outp);    /* packet length */
  651.  
  652.     PUTCHAR(md_len, outp);    /* length of MD */
  653.  
  654.     BCOPY(md, outp, md_len);    /* copy MD to buffer */
  655.     INCPTR(md_len, outp);
  656.  
  657.     BCOPY(hostname, outp, hostname_len); /* append hostname */
  658.     INCPTR(hostname_len, outp);
  659.  
  660.     output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN); /* bomb's away! */
  661. }
  662.