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