xref: /freebsd/usr.sbin/ppp/chap.c (revision 17ee9d00bc1ae1e598c38f25826f861e4bc6c3ce)
1 /*
2  *			PPP CHAP Module
3  *
4  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5  *
6  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the Internet Initiative Japan, Inc.  The name of the
14  * IIJ may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
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  * $Id:$
21  *
22  *	TODO:
23  *		o Imprement retransmission timer.
24  */
25 #include "fsm.h"
26 #include "chap.h"
27 #include "lcpproto.h"
28 #include "lcp.h"
29 #include "hdlc.h"
30 #include "phase.h"
31 #include "vars.h"
32 
33 static int chapid;
34 
35 static char *chapcodes[] = {
36   "???", "CHALLENGE", "RESPONCE", "SUCCESS", "FAILURE"
37 };
38 
39 extern char *AuthGetSecret();
40 
41 void
42 ChapOutput(code, id, ptr, count)
43 u_int code, id;
44 u_char *ptr;
45 int count;
46 {
47   int plen;
48   struct fsmheader lh;
49   struct mbuf *bp;
50 
51   plen =  sizeof(struct fsmheader) + count;
52   lh.code = code;
53   lh.id = id;
54   lh.length = htons(plen);
55   bp = mballoc(plen, MB_FSM);
56   bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
57   if (count)
58     bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
59 #ifdef DEBUG
60   DumpBp(bp);
61 #endif
62   LogPrintf(LOG_LCP, "ChapOutput: %s\n", chapcodes[code]);
63   HdlcOutput(PRI_NORMAL, PROTO_CHAP, bp);
64 }
65 
66 
67 static char challenge_data[80];
68 static int  challenge_len;
69 
70 void
71 SendChapChallenge()
72 {
73   int keylen, len, i;
74   char *cp;
75 
76   srandom(time(NULL));
77   ++chapid;
78 
79   cp = challenge_data;
80   *cp++ = challenge_len = random() % 32 + 16;
81   for (i = 0; i < challenge_len; i++)
82     *cp++ = random() & 0xff;
83   len = strlen(VarAuthName);
84   bcopy(VarAuthName, cp, len);
85   cp += len;
86   ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
87 }
88 
89 #ifdef DEBUG
90 void
91 DumpDigest(mes, cp, len)
92 char *mes;
93 char *cp;
94 {
95   int i;
96 
97   logprintf("%s: ", mes);
98   for (i = 0; i < len; i++) {
99     logprintf(" %02x", *cp++ & 0xff);
100   }
101   logprintf("\n");
102 }
103 #endif
104 
105 void
106 RecvChapTalk(chp, bp)
107 struct fsmheader *chp;
108 struct mbuf *bp;
109 {
110   int valsize, len;
111   int arglen, keylen, namelen;
112   char *cp, *argp, *ap, *name, *digest;
113   char *keyp;
114   MD5_CTX context;                            /* context */
115   char answer[100];
116   char cdigest[16];
117 
118   len = ntohs(chp->length);
119 #ifdef DEBUG
120   logprintf("length: %d\n", len);
121 #endif
122   arglen = len - sizeof(struct fsmheader);
123   cp = (char *)MBUF_CTOP(bp);
124   valsize = *cp++ & 255;
125   name = cp + valsize;
126   namelen = arglen - valsize - 1;
127   name[namelen] = 0;
128   LogPrintf(LOG_PHASE, " Valsize = %d, Name = %s\n", valsize, name);
129 
130   /*
131    * Get a secret key corresponds to the peer
132    */
133   keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
134 
135   switch (chp->code) {
136   case CHAP_CHALLENGE:
137     if (keyp) {
138       keylen = strlen(keyp);
139     } else {
140       keylen = strlen(VarAuthKey);
141       keyp = VarAuthKey;
142     }
143     name = VarAuthName;
144     namelen = strlen(VarAuthName);
145     argp = malloc(1 + valsize + namelen);
146     digest = argp;
147     *digest++ = 16;		/* value size */
148     ap = answer;
149     *ap++ = chp->id;
150     bcopy(keyp, ap, keylen);
151     ap += keylen;
152     bcopy(cp, ap, valsize);
153 #ifdef DEBUG
154     DumpDigest("recv", ap, valsize);
155 #endif
156     ap += valsize;
157     MD5Init(&context);
158     MD5Update(&context, answer, ap - answer);
159     MD5Final(digest, &context);
160 #ifdef DEBUG
161     DumpDigest("answer", digest, 16);
162 #endif
163     bcopy(name, digest + 16, namelen);
164     ap += namelen;
165     /* Send answer to the peer */
166     ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
167     break;
168   case CHAP_RESPONSE:
169     if (keyp) {
170       /*
171        * Compute correct digest value
172        */
173       keylen = strlen(keyp);
174       ap = answer;
175       *ap++ = chp->id;
176       bcopy(keyp, ap, keylen);
177       ap += keylen;
178       MD5Init(&context);
179       MD5Update(&context, answer, ap - answer);
180       MD5Update(&context, challenge_data+1, challenge_len);
181       MD5Final(cdigest, &context);
182 #ifdef DEBUG
183       DumpDigest("got", cp, 16);
184       DumpDigest("expect", cdigest, 16);
185 #endif
186       /*
187        * Compare with the response
188        */
189       if (bcmp(cp, cdigest, 16) == 0) {
190 	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
191 	NewPhase(PHASE_NETWORK);
192 	break;
193       }
194     }
195     /*
196      * Peer is not registerd, or response digest is wrong.
197      */
198     ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
199     LcpClose();
200     break;
201   }
202 }
203 
204 void
205 RecvChapResult(chp, bp)
206 struct fsmheader *chp;
207 struct mbuf *bp;
208 {
209   int len;
210   struct lcpstate *lcp = &LcpInfo;
211 
212   len = ntohs(chp->length);
213 #ifdef DEBUG
214   logprintf("length: %d\n", len);
215 #endif
216   if (chp->code == CHAP_SUCCESS) {
217     if (lcp->auth_iwait == PROTO_CHAP) {
218       lcp->auth_iwait = 0;
219       if (lcp->auth_ineed == 0)
220 	NewPhase(PHASE_NETWORK);
221     }
222   } else {
223     /*
224      * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
225      */
226     ;
227   }
228 }
229 
230 void
231 ChapInput(struct mbuf *bp)
232 {
233   int len = plength(bp);
234   struct fsmheader *chp;
235 
236   if (len >= sizeof(struct fsmheader)) {
237     chp = (struct fsmheader *)MBUF_CTOP(bp);
238     if (len >= ntohs(chp->length)) {
239       if (chp->code < 1 || chp->code > 4)
240 	chp->code = 0;
241       LogPrintf(LOG_LCP, "ChapInput: %s\n", chapcodes[chp->code]);
242 
243       bp->offset += sizeof(struct fsmheader);
244       bp->cnt -= sizeof(struct fsmheader);
245 
246       switch (chp->code) {
247       case CHAP_CHALLENGE:
248       case CHAP_RESPONSE:
249 	RecvChapTalk(chp, bp);
250 	break;
251       case CHAP_SUCCESS:
252       case CHAP_FAILURE:
253 	RecvChapResult(chp, bp);
254 	break;
255       }
256     }
257   }
258   pfree(bp);
259 }
260