1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * $FreeBSD: src/crypto/telnet/libtelnet/auth.c,v 1.3.2.5 2002/04/13 10:59:07 markm Exp $
34 */
35
36#include <sys/cdefs.h>
37
38#ifdef __FBSDID
39__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/auth.c,v 1.3.2.5 2002/04/13 10:59:07 markm Exp $");
40#endif
41
42#ifndef __unused
43#define __unused        __attribute__((__unused__))
44#endif
45
46#ifndef lint
47static const char sccsid[] = "@(#)auth.c	8.3 (Berkeley) 5/30/95";
48#endif /* not lint */
49
50/*
51 * Copyright (C) 1990 by the Massachusetts Institute of Technology
52 *
53 * Export of this software from the United States of America is assumed
54 * to require a specific license from the United States Government.
55 * It is the responsibility of any person or organization contemplating
56 * export to obtain such a license before exporting.
57 *
58 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
59 * distribute this software and its documentation for any purpose and
60 * without fee is hereby granted, provided that the above copyright
61 * notice appear in all copies and that both that copyright notice and
62 * this permission notice appear in supporting documentation, and that
63 * the name of M.I.T. not be used in advertising or publicity pertaining
64 * to distribution of the software without specific, written prior
65 * permission.  M.I.T. makes no representations about the suitability of
66 * this software for any purpose.  It is provided "as is" without express
67 * or implied warranty.
68 */
69
70
71#ifdef	AUTHENTICATION
72#define	AUTH_NAMES
73#include <sys/types.h>
74#include <signal.h>
75#include <stdio.h>
76#include <stdlib.h>
77#include <string.h>
78#include <unistd.h>
79#include <arpa/telnet.h>
80
81#include "encrypt.h"
82#include "auth.h"
83#include "misc-proto.h"
84#include "auth-proto.h"
85
86#define	typemask(x)	((x) > 0 ? 1 << ((x)-1) : 0)
87
88#ifdef	KRB4_ENCPWD
89extern int krb4encpwd_init();
90extern int krb4encpwd_send();
91extern int krb4encpwd_is();
92extern int krb4encpwd_reply();
93extern int krb4encpwd_status();
94extern int krb4encpwd_printsub();
95#endif
96
97#ifdef	RSA_ENCPWD
98extern rsaencpwd_init();
99extern rsaencpwd_send();
100extern rsaencpwd_is();
101extern rsaencpwd_reply();
102extern rsaencpwd_status();
103extern rsaencpwd_printsub();
104#endif
105
106int auth_debug_mode = 0;
107static 	const char	*Name = "Noname";
108static	int	Server = 0;
109static	Authenticator	*authenticated = 0;
110static	int	authenticating = 0;
111static	int	validuser = 0;
112static	unsigned char	_auth_send_data[256];
113static	unsigned char	*auth_send_data;
114static	int	auth_send_cnt = 0;
115
116int auth_onoff(char *type, int on);
117void auth_encrypt_user(char *name);
118
119/*
120 * Authentication types supported.  Plese note that these are stored
121 * in priority order, i.e. try the first one first.
122 */
123Authenticator authenticators[] = {
124#ifdef	KRB5
125# ifdef	ENCRYPTION
126	{ AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
127				kerberos5_init,
128				kerberos5_send,
129				kerberos5_is,
130				kerberos5_reply,
131				kerberos5_status,
132				kerberos5_printsub },
133# endif	/* ENCRYPTION */
134	{ AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
135				kerberos5_init,
136				kerberos5_send,
137				kerberos5_is,
138				kerberos5_reply,
139				kerberos5_status,
140				kerberos5_printsub },
141#endif
142#ifdef	KRB4
143# ifdef ENCRYPTION
144	{ AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
145				kerberos4_init,
146				kerberos4_send,
147				kerberos4_is,
148				kerberos4_reply,
149				kerberos4_status,
150				kerberos4_printsub },
151# endif	/* ENCRYPTION */
152	{ AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
153				kerberos4_init,
154				kerberos4_send,
155				kerberos4_is,
156				kerberos4_reply,
157				kerberos4_status,
158				kerberos4_printsub },
159#endif
160#ifdef	KRB4_ENCPWD
161	{ AUTHTYPE_KRB4_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
162				krb4encpwd_init,
163				krb4encpwd_send,
164				krb4encpwd_is,
165				krb4encpwd_reply,
166				krb4encpwd_status,
167				krb4encpwd_printsub },
168#endif
169#ifdef	RSA_ENCPWD
170	{ AUTHTYPE_RSA_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
171				rsaencpwd_init,
172				rsaencpwd_send,
173				rsaencpwd_is,
174				rsaencpwd_reply,
175				rsaencpwd_status,
176				rsaencpwd_printsub },
177#endif
178#ifdef SRA
179	{ AUTHTYPE_SRA, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
180				sra_init,
181				sra_send,
182				sra_is,
183				sra_reply,
184				sra_status,
185				sra_printsub },
186
187#endif
188	{ 0, 0, 0, 0, 0, 0, 0, 0 },
189};
190
191static Authenticator NoAuth = { 0, 0, 0, 0, 0, 0, 0, 0 };
192
193static int	i_support = 0;
194static int	i_wont_support = 0;
195
196Authenticator *
197findauthenticator(int type, int way)
198{
199	Authenticator *ap = authenticators;
200
201	while (ap->type && (ap->type != type || ap->way != way))
202		++ap;
203	return(ap->type ? ap : 0);
204}
205
206void
207auth_init(const char *name, int server)
208{
209	Authenticator *ap = authenticators;
210
211	Server = server;
212	Name = name;
213
214	i_support = 0;
215	authenticated = 0;
216	authenticating = 0;
217	while (ap->type) {
218		if (!ap->init || (*ap->init)(ap, server)) {
219			i_support |= typemask(ap->type);
220			if (auth_debug_mode)
221				printf(">>>%s: I support auth type %d %d\r\n",
222					Name,
223					ap->type, ap->way);
224		}
225		else if (auth_debug_mode)
226			printf(">>>%s: Init failed: auth type %d %d\r\n",
227				Name, ap->type, ap->way);
228		++ap;
229	}
230}
231
232void
233auth_disable_name(char *name)
234{
235	int x;
236	for (x = 0; x < AUTHTYPE_CNT; ++x) {
237		if (AUTHTYPE_NAME(x) && !strcasecmp(name, AUTHTYPE_NAME(x))) {
238			i_wont_support |= typemask(x);
239			break;
240		}
241	}
242}
243
244int
245getauthmask(char *type, int *maskp)
246{
247	int x;
248
249	if (AUTHTYPE_NAME(0) && !strcasecmp(type, AUTHTYPE_NAME(0))) {
250		*maskp = -1;
251		return(1);
252	}
253
254	for (x = 1; x < AUTHTYPE_CNT; ++x) {
255		if (AUTHTYPE_NAME(x) && !strcasecmp(type, AUTHTYPE_NAME(x))) {
256			*maskp = typemask(x);
257			return(1);
258		}
259	}
260	return(0);
261}
262
263int
264auth_enable(char *type)
265{
266	return(auth_onoff(type, 1));
267}
268
269int
270auth_disable(char *type)
271{
272	return(auth_onoff(type, 0));
273}
274
275int
276auth_onoff(char *type, int on)
277{
278	int i, mask = -1;
279	Authenticator *ap;
280
281	if (!strcasecmp(type, "?") || !strcasecmp(type, "help")) {
282		printf("auth %s 'type'\n", on ? "enable" : "disable");
283		printf("Where 'type' is one of:\n");
284		printf("\t%s\n", AUTHTYPE_NAME(0));
285		mask = 0;
286		for (ap = authenticators; ap->type; ap++) {
287			if ((mask & (i = typemask(ap->type))) != 0)
288				continue;
289			mask |= i;
290			printf("\t%s\n", AUTHTYPE_NAME(ap->type));
291		}
292		return(0);
293	}
294
295	if (!getauthmask(type, &mask)) {
296		printf("%s: invalid authentication type\n", type);
297		return(0);
298	}
299	if (on)
300		i_wont_support &= ~mask;
301	else
302		i_wont_support |= mask;
303	return(1);
304}
305
306int
307auth_togdebug(int on)
308{
309	if (on < 0)
310		auth_debug_mode ^= 1;
311	else
312		auth_debug_mode = on;
313	printf("auth debugging %s\n", auth_debug_mode ? "enabled" : "disabled");
314	return(1);
315}
316
317int
318auth_status(void)
319{
320	Authenticator *ap;
321	int i, mask;
322
323	if (i_wont_support == -1)
324		printf("Authentication disabled\n");
325	else
326		printf("Authentication enabled\n");
327
328	mask = 0;
329	for (ap = authenticators; ap->type; ap++) {
330		if ((mask & (i = typemask(ap->type))) != 0)
331			continue;
332		mask |= i;
333		printf("%s: %s\n", AUTHTYPE_NAME(ap->type),
334			(i_wont_support & typemask(ap->type)) ?
335					"disabled" : "enabled");
336	}
337	return(1);
338}
339
340/*
341 * This routine is called by the server to start authentication
342 * negotiation.
343 */
344void
345auth_request(void)
346{
347	static unsigned char str_request[64] = { IAC, SB,
348						 TELOPT_AUTHENTICATION,
349						 TELQUAL_SEND, };
350	Authenticator *ap = authenticators;
351	unsigned char *e = str_request + 4;
352
353	if (!authenticating) {
354		authenticating = 1;
355		while (ap->type) {
356			if (i_support & ~i_wont_support & typemask(ap->type)) {
357				if (auth_debug_mode) {
358					printf(">>>%s: Sending type %d %d\r\n",
359						Name, ap->type, ap->way);
360				}
361				*e++ = ap->type;
362				*e++ = ap->way;
363			}
364			++ap;
365		}
366		*e++ = IAC;
367		*e++ = SE;
368		net_write(str_request, e - str_request);
369		printsub('>', &str_request[2], e - str_request - 2);
370	}
371}
372
373/*
374 * This is called when an AUTH SEND is received.
375 * It should never arrive on the server side (as only the server can
376 * send an AUTH SEND).
377 * You should probably respond to it if you can...
378 *
379 * If you want to respond to the types out of order (i.e. even
380 * if he sends  LOGIN KERBEROS and you support both, you respond
381 * with KERBEROS instead of LOGIN (which is against what the
382 * protocol says)) you will have to hack this code...
383 */
384void
385auth_send(unsigned char *data, int cnt)
386{
387	Authenticator *ap;
388	static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION,
389					    TELQUAL_IS, AUTHTYPE_NULL, 0,
390					    IAC, SE };
391	if (Server) {
392		if (auth_debug_mode) {
393			printf(">>>%s: auth_send called!\r\n", Name);
394		}
395		return;
396	}
397
398	if (auth_debug_mode) {
399		printf(">>>%s: auth_send got:", Name);
400		printd(data, cnt); printf("\r\n");
401	}
402
403	/*
404	 * Save the data, if it is new, so that we can continue looking
405	 * at it if the authorization we try doesn't work
406	 */
407	if (data < _auth_send_data ||
408	    data > _auth_send_data + sizeof(_auth_send_data)) {
409		auth_send_cnt = (size_t)cnt > sizeof(_auth_send_data)
410					? sizeof(_auth_send_data)
411					: cnt;
412		memmove((void *)_auth_send_data, (void *)data, auth_send_cnt);
413		auth_send_data = _auth_send_data;
414	} else {
415		/*
416		 * This is probably a no-op, but we just make sure
417		 */
418		auth_send_data = data;
419		auth_send_cnt = cnt;
420	}
421	while ((auth_send_cnt -= 2) >= 0) {
422		if (auth_debug_mode)
423			printf(">>>%s: He supports %d\r\n",
424				Name, *auth_send_data);
425		if ((i_support & ~i_wont_support) & typemask(*auth_send_data)) {
426			ap = findauthenticator(auth_send_data[0],
427					       auth_send_data[1]);
428			if (ap && ap->send) {
429				if (auth_debug_mode)
430					printf(">>>%s: Trying %d %d\r\n",
431						Name, auth_send_data[0],
432							auth_send_data[1]);
433				if ((*ap->send)(ap)) {
434					/*
435					 * Okay, we found one we like
436					 * and did it.
437					 * we can go home now.
438					 */
439					if (auth_debug_mode)
440						printf(">>>%s: Using type %d\r\n",
441							Name, *auth_send_data);
442					auth_send_data += 2;
443					return;
444				}
445			}
446			/* else
447			 *	just continue on and look for the
448			 *	next one if we didn't do anything.
449			 */
450		}
451		auth_send_data += 2;
452	}
453	net_write(str_none, sizeof(str_none));
454	printsub('>', &str_none[2], sizeof(str_none) - 2);
455	if (auth_debug_mode)
456		printf(">>>%s: Sent failure message\r\n", Name);
457	auth_finished(0, AUTH_REJECT);
458}
459
460void
461auth_send_retry(void)
462{
463	/*
464	 * if auth_send_cnt <= 0 then auth_send will end up rejecting
465	 * the authentication and informing the other side of this.
466	 */
467	auth_send(auth_send_data, auth_send_cnt);
468}
469
470void
471auth_is(unsigned char *data, int cnt)
472{
473	Authenticator *ap;
474
475	if (cnt < 2)
476		return;
477
478	if (data[0] == AUTHTYPE_NULL) {
479		auth_finished(0, AUTH_REJECT);
480		return;
481	}
482
483	if ((ap = findauthenticator(data[0], data[1]))) {
484		if (ap->is)
485			(*ap->is)(ap, data+2, cnt-2);
486	} else if (auth_debug_mode)
487		printf(">>>%s: Invalid authentication in IS: %d\r\n",
488			Name, *data);
489}
490
491void
492auth_reply(unsigned char *data, int cnt)
493{
494	Authenticator *ap;
495
496	if (cnt < 2)
497		return;
498
499	if ((ap = findauthenticator(data[0], data[1]))) {
500		if (ap->reply)
501			(*ap->reply)(ap, data+2, cnt-2);
502	} else if (auth_debug_mode)
503		printf(">>>%s: Invalid authentication in SEND: %d\r\n",
504			Name, *data);
505}
506
507void
508auth_name(unsigned char *data, int cnt)
509{
510	unsigned char savename[256];
511
512	if (cnt < 1) {
513		if (auth_debug_mode)
514			printf(">>>%s: Empty name in NAME\r\n", Name);
515		return;
516	}
517	if ((size_t)cnt > sizeof(savename) - 1) {
518		if (auth_debug_mode)
519			printf(">>>%s: Name in NAME (%d) exceeds %d length\r\n",
520					Name, cnt, (u_int)sizeof(savename)-1);
521		return;
522	}
523	memmove((void *)savename, (void *)data, cnt);
524	savename[cnt] = '\0';	/* Null terminate */
525	if (auth_debug_mode)
526		printf(">>>%s: Got NAME [%s]\r\n", Name, savename);
527#ifdef	ENCRYPTION
528	auth_encrypt_user(savename);
529#endif
530}
531
532int
533auth_sendname(unsigned char *cp, int len)
534{
535	static unsigned char str_request[256+6]
536			= { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, };
537	unsigned char *e = str_request + 4;
538	unsigned char *ee = &str_request[sizeof(str_request)-2];
539
540	while (--len >= 0) {
541		if ((*e++ = *cp++) == IAC)
542			*e++ = IAC;
543		if (e >= ee)
544			return(0);
545	}
546	*e++ = IAC;
547	*e++ = SE;
548	net_write(str_request, e - str_request);
549	printsub('>', &str_request[2], e - &str_request[2]);
550	return(1);
551}
552
553void
554auth_finished(Authenticator *ap, int result)
555{
556	if (!(authenticated = ap))
557		authenticated = &NoAuth;
558	validuser = result;
559}
560
561/* ARGSUSED */
562static void
563auth_intr(int sig __unused)
564{
565	auth_finished(0, AUTH_REJECT);
566}
567
568int
569auth_wait(char *name)
570{
571	if (auth_debug_mode)
572		printf(">>>%s: in auth_wait.\r\n", Name);
573
574	if (Server && !authenticating)
575		return(0);
576
577	(void) signal(SIGALRM, auth_intr);
578	alarm(30);
579	while (!authenticated)
580		if (telnet_spin())
581			break;
582	alarm(0);
583	(void) signal(SIGALRM, SIG_DFL);
584
585	/*
586	 * Now check to see if the user is valid or not
587	 */
588	if (!authenticated || authenticated == &NoAuth)
589		return(AUTH_REJECT);
590
591	if (validuser == AUTH_VALID)
592		validuser = AUTH_USER;
593
594	if (authenticated->status)
595		validuser = (*authenticated->status)(authenticated,
596						     name, validuser);
597	return(validuser);
598}
599
600void
601auth_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
602{
603	Authenticator *ap;
604
605	if ((ap = findauthenticator(data[1], data[2])) && ap->printsub)
606		(*ap->printsub)(data, cnt, buf, buflen);
607	else
608		auth_gen_printsub(data, cnt, buf, buflen);
609}
610
611void
612auth_gen_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
613{
614	unsigned char *cp;
615	unsigned char tbuf[16];
616
617	cnt -= 3;
618	data += 3;
619	buf[buflen-1] = '\0';
620	buf[buflen-2] = '*';
621	buflen -= 2;
622	for (; cnt > 0; cnt--, data++) {
623		sprintf((char *)tbuf, " %d", *data);
624		for (cp = tbuf; *cp && buflen > 0; --buflen)
625			*buf++ = *cp++;
626		if (buflen <= 0)
627			return;
628	}
629	*buf = '\0';
630}
631#endif
632