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