xref: /freebsd/usr.sbin/ppp/chap.c (revision df7f5d4de4592a8948a25ce01e5bddfbb7ce39dc)
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: chap.c,v 1.11 1997/03/10 08:04:13 ache Exp $
21  *
22  *	TODO:
23  */
24 #include <sys/types.h>
25 #include <time.h>
26 #include "fsm.h"
27 #include "chap.h"
28 #include "lcpproto.h"
29 #include "lcp.h"
30 #include "hdlc.h"
31 #include "phase.h"
32 #include "vars.h"
33 #include "auth.h"
34 
35 static char *chapcodes[] = {
36   "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
37 };
38 
39 struct authinfo AuthChapInfo  = {
40   SendChapChallenge,
41 };
42 
43 extern char *AuthGetSecret();
44 extern int randinit;
45 
46 void
47 ChapOutput(code, id, ptr, count)
48 u_int code, id;
49 u_char *ptr;
50 int count;
51 {
52   int plen;
53   struct fsmheader lh;
54   struct mbuf *bp;
55 
56   plen =  sizeof(struct fsmheader) + count;
57   lh.code = code;
58   lh.id = id;
59   lh.length = htons(plen);
60   bp = mballoc(plen, MB_FSM);
61   bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
62   if (count)
63     bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
64 #ifdef DEBUG
65   DumpBp(bp);
66 #endif
67   LogPrintf(LOG_LCP_BIT, "ChapOutput: %s\n", chapcodes[code]);
68   HdlcOutput(PRI_LINK, PROTO_CHAP, bp);
69 }
70 
71 
72 static char challenge_data[80];
73 static int  challenge_len;
74 
75 void
76 SendChapChallenge(chapid)
77 int chapid;
78 {
79   int len, i;
80   char *cp;
81 
82   if (!randinit) {
83     srandom((unsigned long)(time(NULL) ^ getpid()));
84     randinit = 1;
85   }
86 
87   cp = challenge_data;
88   *cp++ = challenge_len = random() % 32 + 16;
89   for (i = 0; i < challenge_len; i++)
90     *cp++ = random() & 0xff;
91   len = strlen(VarAuthName);
92   bcopy(VarAuthName, cp, len);
93   cp += len;
94   ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
95 }
96 
97 #ifdef DEBUG
98 void
99 DumpDigest(mes, cp, len)
100 char *mes;
101 char *cp;
102 int len;
103 {
104   int i;
105 
106   logprintf("%s: ", mes);
107   for (i = 0; i < len; i++) {
108     logprintf(" %02x", *cp++ & 0xff);
109   }
110   logprintf("\n");
111 }
112 #endif
113 
114 void
115 RecvChapTalk(chp, bp)
116 struct fsmheader *chp;
117 struct mbuf *bp;
118 {
119   int valsize, len;
120   int arglen, keylen, namelen;
121   char *cp, *argp, *ap, *name, *digest;
122   char *keyp;
123   MD5_CTX context;                            /* context */
124   char answer[100];
125   char cdigest[16];
126 
127   len = ntohs(chp->length);
128 #ifdef DEBUG
129   logprintf("length: %d\n", len);
130 #endif
131   arglen = len - sizeof(struct fsmheader);
132   cp = (char *)MBUF_CTOP(bp);
133   valsize = *cp++ & 255;
134   name = cp + valsize;
135   namelen = arglen - valsize - 1;
136   name[namelen] = 0;
137   LogPrintf(LOG_PHASE_BIT, " Valsize = %d, Name = %s\n", valsize, name);
138 
139   /*
140    * Get a secret key corresponds to the peer
141    */
142   keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
143 
144   switch (chp->code) {
145   case CHAP_CHALLENGE:
146     if (keyp) {
147       keylen = strlen(keyp);
148     } else {
149       keylen = strlen(VarAuthKey);
150       keyp = VarAuthKey;
151     }
152     name = VarAuthName;
153     namelen = strlen(VarAuthName);
154     argp = malloc(1 + valsize + namelen + 16);
155     digest = argp;
156     *digest++ = 16;		/* value size */
157     ap = answer;
158     *ap++ = chp->id;
159     bcopy(keyp, ap, keylen);
160     ap += keylen;
161     bcopy(cp, ap, valsize);
162 #ifdef DEBUG
163     DumpDigest("recv", ap, valsize);
164 #endif
165     ap += valsize;
166     MD5Init(&context);
167     MD5Update(&context, answer, ap - answer);
168     MD5Final(digest, &context);
169 #ifdef DEBUG
170     DumpDigest("answer", digest, 16);
171 #endif
172     bcopy(name, digest + 16, namelen);
173     ap += namelen;
174     /* Send answer to the peer */
175     ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
176     free(argp);
177     break;
178   case CHAP_RESPONSE:
179     if (keyp) {
180       /*
181        * Compute correct digest value
182        */
183       keylen = strlen(keyp);
184       ap = answer;
185       *ap++ = chp->id;
186       bcopy(keyp, ap, keylen);
187       ap += keylen;
188       MD5Init(&context);
189       MD5Update(&context, answer, ap - answer);
190       MD5Update(&context, challenge_data+1, challenge_len);
191       MD5Final(cdigest, &context);
192 #ifdef DEBUG
193       DumpDigest("got", cp, 16);
194       DumpDigest("expect", cdigest, 16);
195 #endif
196       /*
197        * Compare with the response
198        */
199       if (bcmp(cp, cdigest, 16) == 0) {
200 	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
201 	NewPhase(PHASE_NETWORK);
202 	break;
203       }
204     }
205     /*
206      * Peer is not registerd, or response digest is wrong.
207      */
208     ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
209     LcpClose();
210     break;
211   }
212 }
213 
214 void
215 RecvChapResult(chp, bp)
216 struct fsmheader *chp;
217 struct mbuf *bp;
218 {
219   int len;
220   struct lcpstate *lcp = &LcpInfo;
221 
222   len = ntohs(chp->length);
223 #ifdef DEBUG
224   logprintf("length: %d\n", len);
225 #endif
226   if (chp->code == CHAP_SUCCESS) {
227     if (lcp->auth_iwait == PROTO_CHAP) {
228       lcp->auth_iwait = 0;
229       if (lcp->auth_ineed == 0)
230 	NewPhase(PHASE_NETWORK);
231     }
232   } else {
233     /*
234      * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
235      */
236     ;
237   }
238 }
239 
240 void
241 ChapInput(struct mbuf *bp)
242 {
243   int len = plength(bp);
244   struct fsmheader *chp;
245 
246   if (len >= sizeof(struct fsmheader)) {
247     chp = (struct fsmheader *)MBUF_CTOP(bp);
248     if (len >= ntohs(chp->length)) {
249       if (chp->code < 1 || chp->code > 4)
250 	chp->code = 0;
251       LogPrintf(LOG_LCP_BIT, "ChapInput: %s\n", chapcodes[chp->code]);
252 
253       bp->offset += sizeof(struct fsmheader);
254       bp->cnt -= sizeof(struct fsmheader);
255 
256       switch (chp->code) {
257       case CHAP_RESPONSE:
258 	StopAuthTimer(&AuthChapInfo);
259 	/* Fall into.. */
260       case CHAP_CHALLENGE:
261 	RecvChapTalk(chp, bp);
262 	break;
263       case CHAP_SUCCESS:
264       case CHAP_FAILURE:
265 	RecvChapResult(chp, bp);
266 	break;
267       }
268     }
269   }
270   pfree(bp);
271 }
272