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