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