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