xref: /freebsd/usr.sbin/ppp/chap.c (revision 952d112864d8008aa87278a30a539d888a8493cd)
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.12 1997/03/17 14:47:55 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     randinit = 1;
84     if (srandomdev() < 0)
85       srandom((unsigned long)(time(NULL) ^ getpid()));
86   }
87 
88   cp = challenge_data;
89   *cp++ = challenge_len = random() % 32 + 16;
90   for (i = 0; i < challenge_len; i++)
91     *cp++ = random() & 0xff;
92   len = strlen(VarAuthName);
93   bcopy(VarAuthName, cp, len);
94   cp += len;
95   ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
96 }
97 
98 #ifdef DEBUG
99 void
100 DumpDigest(mes, cp, len)
101 char *mes;
102 char *cp;
103 int len;
104 {
105   int i;
106 
107   logprintf("%s: ", mes);
108   for (i = 0; i < len; i++) {
109     logprintf(" %02x", *cp++ & 0xff);
110   }
111   logprintf("\n");
112 }
113 #endif
114 
115 void
116 RecvChapTalk(chp, bp)
117 struct fsmheader *chp;
118 struct mbuf *bp;
119 {
120   int valsize, len;
121   int arglen, keylen, namelen;
122   char *cp, *argp, *ap, *name, *digest;
123   char *keyp;
124   MD5_CTX context;                            /* context */
125   char answer[100];
126   char cdigest[16];
127 
128   len = ntohs(chp->length);
129 #ifdef DEBUG
130   logprintf("length: %d\n", len);
131 #endif
132   arglen = len - sizeof(struct fsmheader);
133   cp = (char *)MBUF_CTOP(bp);
134   valsize = *cp++ & 255;
135   name = cp + valsize;
136   namelen = arglen - valsize - 1;
137   name[namelen] = 0;
138   LogPrintf(LOG_PHASE_BIT, " Valsize = %d, Name = %s\n", valsize, name);
139 
140   /*
141    * Get a secret key corresponds to the peer
142    */
143   keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
144 
145   switch (chp->code) {
146   case CHAP_CHALLENGE:
147     if (keyp) {
148       keylen = strlen(keyp);
149     } else {
150       keylen = strlen(VarAuthKey);
151       keyp = VarAuthKey;
152     }
153     name = VarAuthName;
154     namelen = strlen(VarAuthName);
155     argp = malloc(1 + valsize + namelen + 16);
156     digest = argp;
157     *digest++ = 16;		/* value size */
158     ap = answer;
159     *ap++ = chp->id;
160     bcopy(keyp, ap, keylen);
161     ap += keylen;
162     bcopy(cp, ap, valsize);
163 #ifdef DEBUG
164     DumpDigest("recv", ap, valsize);
165 #endif
166     ap += valsize;
167     MD5Init(&context);
168     MD5Update(&context, answer, ap - answer);
169     MD5Final(digest, &context);
170 #ifdef DEBUG
171     DumpDigest("answer", digest, 16);
172 #endif
173     bcopy(name, digest + 16, namelen);
174     ap += namelen;
175     /* Send answer to the peer */
176     ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
177     free(argp);
178     break;
179   case CHAP_RESPONSE:
180     if (keyp) {
181       /*
182        * Compute correct digest value
183        */
184       keylen = strlen(keyp);
185       ap = answer;
186       *ap++ = chp->id;
187       bcopy(keyp, ap, keylen);
188       ap += keylen;
189       MD5Init(&context);
190       MD5Update(&context, answer, ap - answer);
191       MD5Update(&context, challenge_data+1, challenge_len);
192       MD5Final(cdigest, &context);
193 #ifdef DEBUG
194       DumpDigest("got", cp, 16);
195       DumpDigest("expect", cdigest, 16);
196 #endif
197       /*
198        * Compare with the response
199        */
200       if (bcmp(cp, cdigest, 16) == 0) {
201 	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
202 	NewPhase(PHASE_NETWORK);
203 	break;
204       }
205     }
206     /*
207      * Peer is not registerd, or response digest is wrong.
208      */
209     ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
210     LcpClose();
211     break;
212   }
213 }
214 
215 void
216 RecvChapResult(chp, bp)
217 struct fsmheader *chp;
218 struct mbuf *bp;
219 {
220   int len;
221   struct lcpstate *lcp = &LcpInfo;
222 
223   len = ntohs(chp->length);
224 #ifdef DEBUG
225   logprintf("length: %d\n", len);
226 #endif
227   if (chp->code == CHAP_SUCCESS) {
228     if (lcp->auth_iwait == PROTO_CHAP) {
229       lcp->auth_iwait = 0;
230       if (lcp->auth_ineed == 0)
231 	NewPhase(PHASE_NETWORK);
232     }
233   } else {
234     /*
235      * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
236      */
237     ;
238   }
239 }
240 
241 void
242 ChapInput(struct mbuf *bp)
243 {
244   int len = plength(bp);
245   struct fsmheader *chp;
246 
247   if (len >= sizeof(struct fsmheader)) {
248     chp = (struct fsmheader *)MBUF_CTOP(bp);
249     if (len >= ntohs(chp->length)) {
250       if (chp->code < 1 || chp->code > 4)
251 	chp->code = 0;
252       LogPrintf(LOG_LCP_BIT, "ChapInput: %s\n", chapcodes[chp->code]);
253 
254       bp->offset += sizeof(struct fsmheader);
255       bp->cnt -= sizeof(struct fsmheader);
256 
257       switch (chp->code) {
258       case CHAP_RESPONSE:
259 	StopAuthTimer(&AuthChapInfo);
260 	/* Fall into.. */
261       case CHAP_CHALLENGE:
262 	RecvChapTalk(chp, bp);
263 	break;
264       case CHAP_SUCCESS:
265       case CHAP_FAILURE:
266 	RecvChapResult(chp, bp);
267 	break;
268       }
269     }
270   }
271   pfree(bp);
272 }
273