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