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