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