auth.c revision 1.15 1 /* $NetBSD: auth.c,v 1.15 2003/07/15 10:14:55 itojun 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.15 2003/07/15 10:14:55 itojun 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 #ifdef AUTHENTICATION
67 #include <stdio.h>
68 #include <sys/types.h>
69 #include <signal.h>
70 #define AUTH_NAMES
71 #include <arpa/telnet.h>
72 #include <stdlib.h>
73 #include <unistd.h>
74 #ifdef NO_STRING_H
75 #include <strings.h>
76 #else
77 #include <string.h>
78 #endif
79
80 #include "encrypt.h"
81 #include "auth.h"
82 #include "misc-proto.h"
83 #include "auth-proto.h"
84
85 #define typemask(x) (1<<((x)-1))
86
87 #ifdef KRB4_ENCPWD
88 extern krb4encpwd_init();
89 extern krb4encpwd_send();
90 extern krb4encpwd_is();
91 extern krb4encpwd_reply();
92 extern krb4encpwd_status();
93 extern krb4encpwd_printsub();
94 #endif
95
96 #ifdef RSA_ENCPWD
97 extern rsaencpwd_init();
98 extern rsaencpwd_send();
99 extern rsaencpwd_is();
100 extern rsaencpwd_reply();
101 extern rsaencpwd_status();
102 extern rsaencpwd_printsub();
103 #endif
104
105 int auth_debug_mode = 0;
106 static const char *Name = "Noname";
107 static int Server = 0;
108 static Authenticator *authenticated = 0;
109 static int authenticating = 0;
110 static int validuser = 0;
111 static unsigned char _auth_send_data[256];
112 static unsigned char *auth_send_data;
113 static int auth_send_cnt = 0;
114
115 static void auth_intr P((int));
116
117 /*
118 * Authentication types supported. Plese note that these are stored
119 * in priority order, i.e. try the first one first.
120 */
121 Authenticator authenticators[] = {
122 #ifdef SPX
123 { AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
124 spx_init,
125 spx_send,
126 spx_is,
127 spx_reply,
128 spx_status,
129 spx_printsub },
130 { AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
131 spx_init,
132 spx_send,
133 spx_is,
134 spx_reply,
135 spx_status,
136 spx_printsub },
137 #endif
138 #ifdef KRB5
139 # ifdef ENCRYPTION
140 { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
141 kerberos5_init,
142 kerberos5_send,
143 kerberos5_is,
144 kerberos5_reply,
145 kerberos5_status,
146 kerberos5_printsub },
147 # endif /* ENCRYPTION */
148 { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
149 kerberos5_init,
150 kerberos5_send,
151 kerberos5_is,
152 kerberos5_reply,
153 kerberos5_status,
154 kerberos5_printsub },
155 #endif
156 #ifdef KRB4
157 # ifdef ENCRYPTION
158 { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
159 kerberos4_init,
160 kerberos4_send,
161 kerberos4_is,
162 kerberos4_reply,
163 kerberos4_status,
164 kerberos4_printsub },
165 # endif /* ENCRYPTION */
166 { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
167 kerberos4_init,
168 kerberos4_send,
169 kerberos4_is,
170 kerberos4_reply,
171 kerberos4_status,
172 kerberos4_printsub },
173 #endif
174 #ifdef KRB4_ENCPWD
175 { AUTHTYPE_KRB4_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
176 krb4encpwd_init,
177 krb4encpwd_send,
178 krb4encpwd_is,
179 krb4encpwd_reply,
180 krb4encpwd_status,
181 krb4encpwd_printsub },
182 #endif
183 #ifdef RSA_ENCPWD
184 { AUTHTYPE_RSA_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
185 rsaencpwd_init,
186 rsaencpwd_send,
187 rsaencpwd_is,
188 rsaencpwd_reply,
189 rsaencpwd_status,
190 rsaencpwd_printsub },
191 #endif
192 { 0, },
193 };
194
195 static Authenticator NoAuth = { 0 };
196
197 static int i_support = 0;
198 static int i_wont_support = 0;
199
200 Authenticator *
201 findauthenticator(type, way)
202 int type;
203 int way;
204 {
205 Authenticator *ap = authenticators;
206
207 while (ap->type && (ap->type != type || ap->way != way))
208 ++ap;
209 return(ap->type ? ap : 0);
210 }
211
212 void
213 auth_init(name, server)
214 const char *name;
215 int server;
216 {
217 Authenticator *ap = authenticators;
218
219 Server = server;
220 Name = name;
221
222 i_support = 0;
223 authenticated = 0;
224 authenticating = 0;
225 while (ap->type) {
226 if (!ap->init || (*ap->init)(ap, server)) {
227 i_support |= typemask(ap->type);
228 if (auth_debug_mode)
229 printf(">>>%s: I support auth type %d %d\r\n",
230 Name,
231 ap->type, ap->way);
232 }
233 else if (auth_debug_mode)
234 printf(">>>%s: Init failed: auth type %d %d\r\n",
235 Name, ap->type, ap->way);
236 ++ap;
237 }
238 }
239
240 void
241 auth_disable_name(name)
242 char *name;
243 {
244 int x;
245 for (x = 0; x < AUTHTYPE_CNT; ++x) {
246 if (!strcasecmp(name, AUTHTYPE_NAME(x))) {
247 i_wont_support |= typemask(x);
248 break;
249 }
250 }
251 }
252
253 int
254 getauthmask(type, maskp)
255 char *type;
256 int *maskp;
257 {
258 register int x;
259
260 if (!strcasecmp(type, AUTHTYPE_NAME(0))) {
261 *maskp = -1;
262 return(1);
263 }
264
265 for (x = 1; x < AUTHTYPE_CNT; ++x) {
266 if (!strcasecmp(type, AUTHTYPE_NAME(x))) {
267 *maskp = typemask(x);
268 return(1);
269 }
270 }
271 return(0);
272 }
273
274 int
275 auth_enable(type)
276 char *type;
277 {
278 return(auth_onoff(type, 1));
279 }
280
281 int
282 auth_disable(type)
283 char *type;
284 {
285 return(auth_onoff(type, 0));
286 }
287
288 int
289 auth_onoff(type, on)
290 char *type;
291 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(on)
323 int on;
324 {
325 if (on < 0)
326 auth_debug_mode ^= 1;
327 else
328 auth_debug_mode = on;
329 printf("auth debugging %s\n", auth_debug_mode ? "enabled" : "disabled");
330 return(1);
331 }
332
333 int
334 auth_status(s)
335 char *s;
336 {
337 Authenticator *ap;
338 int i, mask;
339
340 if (i_wont_support == -1)
341 printf("Authentication disabled\n");
342 else
343 printf("Authentication enabled\n");
344
345 mask = 0;
346 for (ap = authenticators; ap->type; ap++) {
347 if ((mask & (i = typemask(ap->type))) != 0)
348 continue;
349 mask |= i;
350 printf("%s: %s\n", AUTHTYPE_NAME(ap->type),
351 (i_wont_support & typemask(ap->type)) ?
352 "disabled" : "enabled");
353 }
354 return(1);
355 }
356
357 /*
358 * This routine is called by the server to start authentication
359 * negotiation.
360 */
361 void
362 auth_request()
363 {
364 static unsigned char str_request[64] = { IAC, SB,
365 TELOPT_AUTHENTICATION,
366 TELQUAL_SEND, };
367 Authenticator *ap = authenticators;
368 unsigned char *e = str_request + 4;
369
370 if (!authenticating) {
371 authenticating = 1;
372 while (ap->type) {
373 if (i_support & ~i_wont_support & typemask(ap->type)) {
374 if (auth_debug_mode) {
375 printf(">>>%s: Sending type %d %d\r\n",
376 Name, ap->type, ap->way);
377 }
378 *e++ = ap->type;
379 *e++ = ap->way;
380 }
381 ++ap;
382 }
383 *e++ = IAC;
384 *e++ = SE;
385 telnet_net_write(str_request, e - str_request);
386 printsub('>', &str_request[2], e - str_request - 2);
387 }
388 }
389
390 /*
391 * This is called when an AUTH SEND is received.
392 * It should never arrive on the server side (as only the server can
393 * send an AUTH SEND).
394 * You should probably respond to it if you can...
395 *
396 * If you want to respond to the types out of order (i.e. even
397 * if he sends LOGIN KERBEROS and you support both, you respond
398 * with KERBEROS instead of LOGIN (which is against what the
399 * protocol says)) you will have to hack this code...
400 */
401 void
402 auth_send(data, cnt)
403 unsigned char *data;
404 int cnt;
405 {
406 Authenticator *ap;
407 static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION,
408 TELQUAL_IS, AUTHTYPE_NULL, 0,
409 IAC, SE };
410 if (Server) {
411 if (auth_debug_mode) {
412 printf(">>>%s: auth_send called!\r\n", Name);
413 }
414 return;
415 }
416
417 if (auth_debug_mode) {
418 printf(">>>%s: auth_send got:", Name);
419 printd(data, cnt); printf("\r\n");
420 }
421
422 /*
423 * Save the data, if it is new, so that we can continue looking
424 * at it if the authorization we try doesn't work
425 */
426 if (data < _auth_send_data ||
427 data > _auth_send_data + sizeof(_auth_send_data)) {
428 auth_send_cnt = cnt > sizeof(_auth_send_data)
429 ? sizeof(_auth_send_data)
430 : cnt;
431 memmove((void *)_auth_send_data, (void *)data, auth_send_cnt);
432 auth_send_data = _auth_send_data;
433 } else {
434 /*
435 * This is probably a no-op, but we just make sure
436 */
437 auth_send_data = data;
438 auth_send_cnt = cnt;
439 }
440 while ((auth_send_cnt -= 2) >= 0) {
441 if (auth_debug_mode)
442 printf(">>>%s: He supports %d\r\n",
443 Name, *auth_send_data);
444 if ((i_support & ~i_wont_support) & typemask(*auth_send_data)) {
445 ap = findauthenticator(auth_send_data[0],
446 auth_send_data[1]);
447 if (ap && ap->send) {
448 if (auth_debug_mode)
449 printf(">>>%s: Trying %d %d\r\n",
450 Name, auth_send_data[0],
451 auth_send_data[1]);
452 if ((*ap->send)(ap)) {
453 /*
454 * Okay, we found one we like
455 * and did it.
456 * we can go home now.
457 */
458 if (auth_debug_mode)
459 printf(">>>%s: Using type %d\r\n",
460 Name, *auth_send_data);
461 auth_send_data += 2;
462 return;
463 }
464 }
465 /* else
466 * just continue on and look for the
467 * next one if we didn't do anything.
468 */
469 }
470 auth_send_data += 2;
471 }
472 telnet_net_write(str_none, sizeof(str_none));
473 printsub('>', &str_none[2], sizeof(str_none) - 2);
474 if (auth_debug_mode)
475 printf(">>>%s: Sent failure message\r\n", Name);
476 auth_finished(0, AUTH_REJECT);
477 #ifdef KANNAN
478 /*
479 * We requested strong authentication, however no mechanisms worked.
480 * Therefore, exit on client end.
481 */
482 printf("Unable to securely authenticate user ... exit\n");
483 exit(0);
484 #endif /* KANNAN */
485 }
486
487 void
488 auth_send_retry()
489 {
490 /*
491 * if auth_send_cnt <= 0 then auth_send will end up rejecting
492 * the authentication and informing the other side of this.
493 */
494 auth_send(auth_send_data, auth_send_cnt);
495 }
496
497 void
498 auth_is(data, cnt)
499 unsigned char *data;
500 int cnt;
501 {
502 Authenticator *ap;
503
504 if (cnt < 2)
505 return;
506
507 if (data[0] == AUTHTYPE_NULL) {
508 auth_finished(0, AUTH_REJECT);
509 return;
510 }
511
512 if ((ap = findauthenticator(data[0], data[1])) != NULL) {
513 if (ap->is)
514 (*ap->is)(ap, data+2, cnt-2);
515 } else if (auth_debug_mode)
516 printf(">>>%s: Invalid authentication in IS: %d\r\n",
517 Name, *data);
518 }
519
520 void
521 auth_reply(data, cnt)
522 unsigned char *data;
523 int cnt;
524 {
525 Authenticator *ap;
526
527 if (cnt < 2)
528 return;
529
530 if ((ap = findauthenticator(data[0], data[1])) != NULL) {
531 if (ap->reply)
532 (*ap->reply)(ap, data+2, cnt-2);
533 } else if (auth_debug_mode)
534 printf(">>>%s: Invalid authentication in SEND: %d\r\n",
535 Name, *data);
536 }
537
538 void
539 auth_name(data, cnt)
540 unsigned char *data;
541 int cnt;
542 {
543 unsigned char savename[256];
544
545 if (cnt < 1) {
546 if (auth_debug_mode)
547 printf(">>>%s: Empty name in NAME\r\n", Name);
548 return;
549 }
550 if (cnt > sizeof(savename) - 1) {
551 if (auth_debug_mode)
552 printf(">>>%s: Name in NAME (%d) exceeds %ld length\r\n",
553 Name, cnt, (long)sizeof(savename)-1);
554 return;
555 }
556 memmove((void *)savename, (void *)data, cnt);
557 savename[cnt] = '\0'; /* Null terminate */
558 if (auth_debug_mode)
559 printf(">>>%s: Got NAME [%s]\r\n", Name, savename);
560 auth_encrypt_user(savename);
561 }
562
563 int
564 auth_sendname(cp, len)
565 unsigned char *cp;
566 int len;
567 {
568 static unsigned char str_request[256+6]
569 = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, };
570 register unsigned char *e = str_request + 4;
571 register unsigned char *ee = &str_request[sizeof(str_request)-2];
572
573 while (--len >= 0) {
574 if ((*e++ = *cp++) == IAC)
575 *e++ = IAC;
576 if (e >= ee)
577 return(0);
578 }
579 *e++ = IAC;
580 *e++ = SE;
581 telnet_net_write(str_request, e - str_request);
582 printsub('>', &str_request[2], e - &str_request[2]);
583 return(1);
584 }
585
586 void
587 auth_finished(ap, result)
588 Authenticator *ap;
589 int result;
590 {
591 if (!(authenticated = ap))
592 authenticated = &NoAuth;
593 validuser = result;
594 }
595
596 /* ARGSUSED */
597 static void
598 auth_intr(sig)
599 int sig;
600 {
601 auth_finished(0, AUTH_REJECT);
602 }
603
604 int
605 auth_wait(name, l)
606 char *name;
607 size_t l;
608 {
609 if (auth_debug_mode)
610 printf(">>>%s: in auth_wait.\r\n", Name);
611
612 if (Server && !authenticating)
613 return(0);
614
615 (void) signal(SIGALRM, auth_intr);
616 alarm(30);
617 while (!authenticated)
618 if (telnet_spin())
619 break;
620 alarm(0);
621 (void) signal(SIGALRM, SIG_DFL);
622
623 /*
624 * Now check to see if the user is valid or not
625 */
626 if (!authenticated || authenticated == &NoAuth)
627 return(AUTH_REJECT);
628
629 if (validuser == AUTH_VALID)
630 validuser = AUTH_USER;
631
632 if (authenticated->status)
633 validuser = (*authenticated->status)(authenticated,
634 name, l, validuser);
635 return(validuser);
636 }
637
638 void
639 auth_debug(mode)
640 int mode;
641 {
642 auth_debug_mode = mode;
643 }
644
645 void
646 auth_printsub(data, cnt, buf, buflen)
647 unsigned char *data, *buf;
648 int cnt, buflen;
649 {
650 Authenticator *ap;
651
652 if ((ap = findauthenticator(data[1], data[2])) && ap->printsub)
653 (*ap->printsub)(data, cnt, buf, buflen);
654 else
655 auth_gen_printsub(data, cnt, buf, buflen);
656 }
657
658 void
659 auth_gen_printsub(data, cnt, buf, buflen)
660 unsigned char *data, *buf;
661 int cnt, buflen;
662 {
663 register unsigned char *cp;
664 unsigned char tbuf[16];
665
666 cnt -= 3;
667 data += 3;
668 buf[buflen-1] = '\0';
669 buf[buflen-2] = '*';
670 buflen -= 2;
671 for (; cnt > 0; cnt--, data++) {
672 snprintf((char *)tbuf, sizeof(tbuf), " %d", *data);
673 for (cp = tbuf; *cp && buflen > 0; --buflen)
674 *buf++ = *cp++;
675 if (buflen <= 0)
676 return;
677 }
678 *buf = '\0';
679 }
680 #endif
681