auth.c revision 1.11 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