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