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