]> git.ozlabs.org Git - ppp.git/blob - pppd/chap-new.c
Add extra baud rates >= 1Mbaud.
[ppp.git] / pppd / chap-new.c
1 /*
2  * chap-new.c - New CHAP implementation.
3  *
4  * Copyright (c) 2003 Paul Mackerras. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. The name(s) of the authors of this software must not be used to
14  *    endorse or promote products derived from this software without
15  *    prior written permission.
16  *
17  * 3. Redistributions of any form whatsoever must retain the following
18  *    acknowledgment:
19  *    "This product includes software developed by Paul Mackerras
20  *     <paulus@samba.org>".
21  *
22  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
23  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
24  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
26  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
28  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29  */
30
31 #define RCSID   "$Id: chap-new.c,v 1.8 2005/07/13 10:41:58 paulus Exp $"
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include "pppd.h"
36 #include "chap-new.h"
37 #include "chap-md5.h"
38
39 #ifdef CHAPMS
40 #include "chap_ms.h"
41 #define MDTYPE_ALL (MDTYPE_MICROSOFT_V2 | MDTYPE_MICROSOFT | MDTYPE_MD5)
42 #else
43 #define MDTYPE_ALL (MDTYPE_MD5)
44 #endif
45
46 int chap_mdtype_all = MDTYPE_ALL;
47
48 /* Hook for a plugin to validate CHAP challenge */
49 int (*chap_verify_hook)(char *name, char *ourname, int id,
50                         struct chap_digest_type *digest,
51                         unsigned char *challenge, unsigned char *response,
52                         char *message, int message_space) = NULL;
53
54 /*
55  * Option variables.
56  */
57 int chap_timeout_time = 3;
58 int chap_max_transmits = 10;
59 int chap_rechallenge_time = 0;
60
61 /*
62  * Command-line options.
63  */
64 static option_t chap_option_list[] = {
65         { "chap-restart", o_int, &chap_timeout_time,
66           "Set timeout for CHAP", OPT_PRIO },
67         { "chap-max-challenge", o_int, &chap_max_transmits,
68           "Set max #xmits for challenge", OPT_PRIO },
69         { "chap-interval", o_int, &chap_rechallenge_time,
70           "Set interval for rechallenge", OPT_PRIO },
71         { NULL }
72 };
73
74 /*
75  * Internal state.
76  */
77 static struct chap_client_state {
78         int flags;
79         char *name;
80         struct chap_digest_type *digest;
81         unsigned char priv[64];         /* private area for digest's use */
82 } client;
83
84 /*
85  * These limits apply to challenge and response packets we send.
86  * The +4 is the +1 that we actually need rounded up.
87  */
88 #define CHAL_MAX_PKTLEN (PPP_HDRLEN + CHAP_HDRLEN + 4 + MAX_CHALLENGE_LEN + MAXNAMELEN)
89 #define RESP_MAX_PKTLEN (PPP_HDRLEN + CHAP_HDRLEN + 4 + MAX_RESPONSE_LEN + MAXNAMELEN)
90
91 static struct chap_server_state {
92         int flags;
93         int id;
94         char *name;
95         struct chap_digest_type *digest;
96         int challenge_xmits;
97         int challenge_pktlen;
98         unsigned char challenge[CHAL_MAX_PKTLEN];
99         char message[256];
100 } server;
101
102 /* Values for flags in chap_client_state and chap_server_state */
103 #define LOWERUP                 1
104 #define AUTH_STARTED            2
105 #define AUTH_DONE               4
106 #define AUTH_FAILED             8
107 #define TIMEOUT_PENDING         0x10
108 #define CHALLENGE_VALID         0x20
109
110 /*
111  * Prototypes.
112  */
113 static void chap_init(int unit);
114 static void chap_lowerup(int unit);
115 static void chap_lowerdown(int unit);
116 static void chap_timeout(void *arg);
117 static void chap_generate_challenge(struct chap_server_state *ss);
118 static void chap_handle_response(struct chap_server_state *ss, int code,
119                 unsigned char *pkt, int len);
120 static int chap_verify_response(char *name, char *ourname, int id,
121                 struct chap_digest_type *digest,
122                 unsigned char *challenge, unsigned char *response,
123                 char *message, int message_space);
124 static void chap_respond(struct chap_client_state *cs, int id,
125                 unsigned char *pkt, int len);
126 static void chap_handle_status(struct chap_client_state *cs, int code, int id,
127                 unsigned char *pkt, int len);
128 static void chap_protrej(int unit);
129 static void chap_input(int unit, unsigned char *pkt, int pktlen);
130 static int chap_print_pkt(unsigned char *p, int plen,
131                 void (*printer) __P((void *, char *, ...)), void *arg);
132
133 /* List of digest types that we know about */
134 static struct chap_digest_type *chap_digests;
135
136 /*
137  * chap_init - reset to initial state.
138  */
139 static void
140 chap_init(int unit)
141 {
142         memset(&client, 0, sizeof(client));
143         memset(&server, 0, sizeof(server));
144
145         chap_md5_init();
146 #ifdef CHAPMS
147         chapms_init();
148 #endif
149 }
150
151 /*
152  * Add a new digest type to the list.
153  */
154 void
155 chap_register_digest(struct chap_digest_type *dp)
156 {
157         dp->next = chap_digests;
158         chap_digests = dp;
159 }
160
161 /*
162  * chap_lowerup - we can start doing stuff now.
163  */
164 static void
165 chap_lowerup(int unit)
166 {
167         struct chap_client_state *cs = &client;
168         struct chap_server_state *ss = &server;
169
170         cs->flags |= LOWERUP;
171         ss->flags |= LOWERUP;
172         if (ss->flags & AUTH_STARTED)
173                 chap_timeout(ss);
174 }
175
176 static void
177 chap_lowerdown(int unit)
178 {
179         struct chap_client_state *cs = &client;
180         struct chap_server_state *ss = &server;
181
182         cs->flags = 0;
183         if (ss->flags & TIMEOUT_PENDING)
184                 UNTIMEOUT(chap_timeout, ss);
185         ss->flags = 0;
186 }
187
188 /*
189  * chap_auth_peer - Start authenticating the peer.
190  * If the lower layer is already up, we start sending challenges,
191  * otherwise we wait for the lower layer to come up.
192  */
193 void
194 chap_auth_peer(int unit, char *our_name, int digest_code)
195 {
196         struct chap_server_state *ss = &server;
197         struct chap_digest_type *dp;
198
199         if (ss->flags & AUTH_STARTED) {
200                 error("CHAP: peer authentication already started!");
201                 return;
202         }
203         for (dp = chap_digests; dp != NULL; dp = dp->next)
204                 if (dp->code == digest_code)
205                         break;
206         if (dp == NULL)
207                 fatal("CHAP digest 0x%x requested but not available",
208                       digest_code);
209
210         ss->digest = dp;
211         ss->name = our_name;
212         /* Start with a random ID value */
213         ss->id = (unsigned char)(drand48() * 256);
214         ss->flags |= AUTH_STARTED;
215         if (ss->flags & LOWERUP)
216                 chap_timeout(ss);
217 }
218
219 /*
220  * chap_auth_with_peer - Prepare to authenticate ourselves to the peer.
221  * There isn't much to do until we receive a challenge.
222  */
223 void
224 chap_auth_with_peer(int unit, char *our_name, int digest_code)
225 {
226         struct chap_client_state *cs = &client;
227         struct chap_digest_type *dp;
228
229         if (cs->flags & AUTH_STARTED) {
230                 error("CHAP: authentication with peer already started!");
231                 return;
232         }
233         for (dp = chap_digests; dp != NULL; dp = dp->next)
234                 if (dp->code == digest_code)
235                         break;
236         if (dp == NULL)
237                 fatal("CHAP digest 0x%x requested but not available",
238                       digest_code);
239
240         cs->digest = dp;
241         cs->name = our_name;
242         cs->flags |= AUTH_STARTED;
243 }
244
245 /*
246  * chap_timeout - It's time to send another challenge to the peer.
247  * This could be either a retransmission of a previous challenge,
248  * or a new challenge to start re-authentication.
249  */
250 static void
251 chap_timeout(void *arg)
252 {
253         struct chap_server_state *ss = arg;
254
255         ss->flags &= ~TIMEOUT_PENDING;
256         if ((ss->flags & CHALLENGE_VALID) == 0) {
257                 ss->challenge_xmits = 0;
258                 chap_generate_challenge(ss);
259                 ss->flags |= CHALLENGE_VALID;
260         } else if (ss->challenge_xmits >= chap_max_transmits) {
261                 ss->flags &= ~CHALLENGE_VALID;
262                 ss->flags |= AUTH_DONE | AUTH_FAILED;
263                 auth_peer_fail(0, PPP_CHAP);
264                 return;
265         }
266
267         output(0, ss->challenge, ss->challenge_pktlen);
268         ++ss->challenge_xmits;
269         ss->flags |= TIMEOUT_PENDING;
270         TIMEOUT(chap_timeout, arg, chap_timeout_time);
271 }
272
273 /*
274  * chap_generate_challenge - generate a challenge string and format
275  * the challenge packet in ss->challenge_pkt.
276  */
277 static void
278 chap_generate_challenge(struct chap_server_state *ss)
279 {
280         int clen = 1, nlen, len;
281         unsigned char *p;
282
283         p = ss->challenge;
284         MAKEHEADER(p, PPP_CHAP);
285         p += CHAP_HDRLEN;
286         ss->digest->generate_challenge(p);
287         clen = *p;
288         nlen = strlen(ss->name);
289         memcpy(p + 1 + clen, ss->name, nlen);
290
291         len = CHAP_HDRLEN + 1 + clen + nlen;
292         ss->challenge_pktlen = PPP_HDRLEN + len;
293
294         p = ss->challenge + PPP_HDRLEN;
295         p[0] = CHAP_CHALLENGE;
296         p[1] = ++ss->id;
297         p[2] = len >> 8;
298         p[3] = len;
299 }
300
301 /*
302  * chap_handle_response - check the response to our challenge.
303  */
304 static void
305 chap_handle_response(struct chap_server_state *ss, int id,
306                      unsigned char *pkt, int len)
307 {
308         int response_len, ok, mlen;
309         unsigned char *response, *p;
310         char *name = NULL;      /* initialized to shut gcc up */
311         int (*verifier)(char *, char *, int, struct chap_digest_type *,
312                 unsigned char *, unsigned char *, char *, int);
313         char rname[MAXNAMELEN+1];
314
315         if ((ss->flags & LOWERUP) == 0)
316                 return;
317         if (id != ss->challenge[PPP_HDRLEN+1] || len < 2)
318                 return;
319         if (ss->flags & CHALLENGE_VALID) {
320                 response = pkt;
321                 GETCHAR(response_len, pkt);
322                 len -= response_len + 1;        /* length of name */
323                 name = (char *)pkt + response_len;
324                 if (len < 0)
325                         return;
326
327                 if (ss->flags & TIMEOUT_PENDING) {
328                         ss->flags &= ~TIMEOUT_PENDING;
329                         UNTIMEOUT(chap_timeout, ss);
330                 }
331
332                 if (explicit_remote) {
333                         name = remote_name;
334                 } else {
335                         /* Null terminate and clean remote name. */
336                         slprintf(rname, sizeof(rname), "%.*v", len, name);
337                         name = rname;
338                 }
339
340                 if (chap_verify_hook)
341                         verifier = chap_verify_hook;
342                 else
343                         verifier = chap_verify_response;
344                 ok = (*verifier)(name, ss->name, id, ss->digest,
345                                  ss->challenge + PPP_HDRLEN + CHAP_HDRLEN,
346                                  response, ss->message, sizeof(ss->message));
347                 if (!ok || !auth_number()) {
348                         ss->flags |= AUTH_FAILED;
349                         warn("Peer %q failed CHAP authentication", name);
350                 }
351         } else if ((ss->flags & AUTH_DONE) == 0)
352                 return;
353
354         /* send the response */
355         p = outpacket_buf;
356         MAKEHEADER(p, PPP_CHAP);
357         mlen = strlen(ss->message);
358         len = CHAP_HDRLEN + mlen;
359         p[0] = (ss->flags & AUTH_FAILED)? CHAP_FAILURE: CHAP_SUCCESS;
360         p[1] = id;
361         p[2] = len >> 8;
362         p[3] = len;
363         if (mlen > 0)
364                 memcpy(p + CHAP_HDRLEN, ss->message, mlen);
365         output(0, outpacket_buf, PPP_HDRLEN + len);
366
367         if (ss->flags & CHALLENGE_VALID) {
368                 ss->flags &= ~CHALLENGE_VALID;
369                 if (ss->flags & AUTH_FAILED) {
370                         auth_peer_fail(0, PPP_CHAP);
371                 } else {
372                         if ((ss->flags & AUTH_DONE) == 0)
373                                 auth_peer_success(0, PPP_CHAP,
374                                                   ss->digest->code,
375                                                   name, strlen(name));
376                         if (chap_rechallenge_time) {
377                                 ss->flags |= TIMEOUT_PENDING;
378                                 TIMEOUT(chap_timeout, ss,
379                                         chap_rechallenge_time);
380                         }
381                 }
382                 ss->flags |= AUTH_DONE;
383         }
384 }
385
386 /*
387  * chap_verify_response - check whether the peer's response matches
388  * what we think it should be.  Returns 1 if it does (authentication
389  * succeeded), or 0 if it doesn't.
390  */
391 static int
392 chap_verify_response(char *name, char *ourname, int id,
393                      struct chap_digest_type *digest,
394                      unsigned char *challenge, unsigned char *response,
395                      char *message, int message_space)
396 {
397         int ok;
398         unsigned char secret[MAXSECRETLEN];
399         int secret_len;
400
401         /* Get the secret that the peer is supposed to know */
402         if (!get_secret(0, name, ourname, (char *)secret, &secret_len, 1)) {
403                 error("No CHAP secret found for authenticating %q", name);
404                 return 0;
405         }
406
407         ok = digest->verify_response(id, name, secret, secret_len, challenge,
408                                      response, message, message_space);
409         memset(secret, 0, sizeof(secret));
410
411         return ok;
412 }
413
414 /*
415  * chap_respond - Generate and send a response to a challenge.
416  */
417 static void
418 chap_respond(struct chap_client_state *cs, int id,
419              unsigned char *pkt, int len)
420 {
421         int clen, nlen;
422         int secret_len;
423         unsigned char *p;
424         unsigned char response[RESP_MAX_PKTLEN];
425         char rname[MAXNAMELEN+1];
426         char secret[MAXSECRETLEN+1];
427
428         if ((cs->flags & (LOWERUP | AUTH_STARTED)) != (LOWERUP | AUTH_STARTED))
429                 return;         /* not ready */
430         if (len < 2 || len < pkt[0] + 1)
431                 return;         /* too short */
432         clen = pkt[0];
433         nlen = len - (clen + 1);
434
435         /* Null terminate and clean remote name. */
436         slprintf(rname, sizeof(rname), "%.*v", nlen, pkt + clen + 1);
437
438         /* Microsoft doesn't send their name back in the PPP packet */
439         if (explicit_remote || (remote_name[0] != 0 && rname[0] == 0))
440                 strlcpy(rname, remote_name, sizeof(rname));
441
442         /* get secret for authenticating ourselves with the specified host */
443         if (!get_secret(0, cs->name, rname, secret, &secret_len, 0)) {
444                 secret_len = 0; /* assume null secret if can't find one */
445                 warn("No CHAP secret found for authenticating us to %q", rname);
446         }
447
448         p = response;
449         MAKEHEADER(p, PPP_CHAP);
450         p += CHAP_HDRLEN;
451
452         cs->digest->make_response(p, id, cs->name, pkt,
453                                   secret, secret_len, cs->priv);
454         memset(secret, 0, secret_len);
455
456         clen = *p;
457         nlen = strlen(cs->name);
458         memcpy(p + clen + 1, cs->name, nlen);
459
460         p = response + PPP_HDRLEN;
461         len = CHAP_HDRLEN + clen + 1 + nlen;
462         p[0] = CHAP_RESPONSE;
463         p[1] = id;
464         p[2] = len >> 8;
465         p[3] = len;
466
467         output(0, response, PPP_HDRLEN + len);
468 }
469
470 static void
471 chap_handle_status(struct chap_client_state *cs, int code, int id,
472                    unsigned char *pkt, int len)
473 {
474         const char *msg = NULL;
475
476         if ((cs->flags & (AUTH_DONE|AUTH_STARTED|LOWERUP))
477             != (AUTH_STARTED|LOWERUP))
478                 return;
479         cs->flags |= AUTH_DONE;
480
481         if (code == CHAP_SUCCESS) {
482                 /* used for MS-CHAP v2 mutual auth, yuck */
483                 if (cs->digest->check_success != NULL) {
484                         if (!(*cs->digest->check_success)(pkt, len, cs->priv))
485                                 code = CHAP_FAILURE;
486                 } else
487                         msg = "CHAP authentication succeeded";
488         } else {
489                 if (cs->digest->handle_failure != NULL)
490                         (*cs->digest->handle_failure)(pkt, len);
491                 else
492                         msg = "CHAP authentication failed";
493         }
494         if (msg) {
495                 if (len > 0)
496                         info("%s: %.*v", msg, len, pkt);
497                 else
498                         info("%s", msg);
499         }
500         if (code == CHAP_SUCCESS)
501                 auth_withpeer_success(0, PPP_CHAP, cs->digest->code);
502         else {
503                 cs->flags |= AUTH_FAILED;
504                 error("CHAP authentication failed");
505                 auth_withpeer_fail(0, PPP_CHAP);
506         }
507 }
508
509 static void
510 chap_input(int unit, unsigned char *pkt, int pktlen)
511 {
512         struct chap_client_state *cs = &client;
513         struct chap_server_state *ss = &server;
514         unsigned char code, id;
515         int len;
516
517         if (pktlen < CHAP_HDRLEN)
518                 return;
519         GETCHAR(code, pkt);
520         GETCHAR(id, pkt);
521         GETSHORT(len, pkt);
522         if (len < CHAP_HDRLEN || len > pktlen)
523                 return;
524         len -= CHAP_HDRLEN;
525
526         switch (code) {
527         case CHAP_CHALLENGE:
528                 chap_respond(cs, id, pkt, len);
529                 break;
530         case CHAP_RESPONSE:
531                 chap_handle_response(ss, id, pkt, len);
532                 break;
533         case CHAP_FAILURE:
534         case CHAP_SUCCESS:
535                 chap_handle_status(cs, code, id, pkt, len);
536                 break;
537         }
538 }
539
540 static void
541 chap_protrej(int unit)
542 {
543         struct chap_client_state *cs = &client;
544         struct chap_server_state *ss = &server;
545
546         if (ss->flags & TIMEOUT_PENDING) {
547                 ss->flags &= ~TIMEOUT_PENDING;
548                 UNTIMEOUT(chap_timeout, ss);
549         }
550         if (ss->flags & AUTH_STARTED) {
551                 ss->flags = 0;
552                 auth_peer_fail(0, PPP_CHAP);
553         }
554         if ((cs->flags & (AUTH_STARTED|AUTH_DONE)) == AUTH_STARTED) {
555                 cs->flags &= ~AUTH_STARTED;
556                 error("CHAP authentication failed due to protocol-reject");
557                 auth_withpeer_fail(0, PPP_CHAP);
558         }
559 }
560
561 /*
562  * chap_print_pkt - print the contents of a CHAP packet.
563  */
564 static char *chap_code_names[] = {
565         "Challenge", "Response", "Success", "Failure"
566 };
567
568 static int
569 chap_print_pkt(unsigned char *p, int plen,
570                void (*printer) __P((void *, char *, ...)), void *arg)
571 {
572         int code, id, len;
573         int clen, nlen;
574         unsigned char x;
575
576         if (plen < CHAP_HDRLEN)
577                 return 0;
578         GETCHAR(code, p);
579         GETCHAR(id, p);
580         GETSHORT(len, p);
581         if (len < CHAP_HDRLEN || len > plen)
582                 return 0;
583
584         if (code >= 1 && code <= sizeof(chap_code_names) / sizeof(char *))
585                 printer(arg, " %s", chap_code_names[code-1]);
586         else
587                 printer(arg, " code=0x%x", code);
588         printer(arg, " id=0x%x", id);
589         len -= CHAP_HDRLEN;
590         switch (code) {
591         case CHAP_CHALLENGE:
592         case CHAP_RESPONSE:
593                 if (len < 1)
594                         break;
595                 clen = p[0];
596                 if (len < clen + 1)
597                         break;
598                 ++p;
599                 nlen = len - clen - 1;
600                 printer(arg, " <");
601                 for (; clen > 0; --clen) {
602                         GETCHAR(x, p);
603                         printer(arg, "%.2x", x);
604                 }
605                 printer(arg, ">, name = ");
606                 print_string((char *)p, nlen, printer, arg);
607                 break;
608         case CHAP_FAILURE:
609         case CHAP_SUCCESS:
610                 printer(arg, " ");
611                 print_string((char *)p, len, printer, arg);
612                 break;
613         default:
614                 for (clen = len; clen > 0; --clen) {
615                         GETCHAR(x, p);
616                         printer(arg, " %.2x", x);
617                 }
618         }
619
620         return len + CHAP_HDRLEN;
621 }
622
623 struct protent chap_protent = {
624         PPP_CHAP,
625         chap_init,
626         chap_input,
627         chap_protrej,
628         chap_lowerup,
629         chap_lowerdown,
630         NULL,           /* open */
631         NULL,           /* close */
632         chap_print_pkt,
633         NULL,           /* datainput */
634         1,              /* enabled_flag */
635         "CHAP",         /* name */
636         NULL,           /* data_name */
637         chap_option_list,
638         NULL,           /* check_options */
639 };