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