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