auth.c revision 1.13 1 /* $NetBSD: auth.c,v 1.13 2003/07/14 08:36:27 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.13 2003/07/14 08:36:27 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)
606 char *name;
607 {
608 if (auth_debug_mode)
609 printf(">>>%s: in auth_wait.\r\n", Name);
610
611 if (Server && !authenticating)
612 return(0);
613
614 (void) signal(SIGALRM, auth_intr);
615 alarm(30);
616 while (!authenticated)
617 if (telnet_spin())
618 break;
619 alarm(0);
620 (void) signal(SIGALRM, SIG_DFL);
621
622 /*
623 * Now check to see if the user is valid or not
624 */
625 if (!authenticated || authenticated == &NoAuth)
626 return(AUTH_REJECT);
627
628 if (validuser == AUTH_VALID)
629 validuser = AUTH_USER;
630
631 if (authenticated->status)
632 validuser = (*authenticated->status)(authenticated,
633 name, validuser);
634 return(validuser);
635 }
636
637 void
638 auth_debug(mode)
639 int mode;
640 {
641 auth_debug_mode = mode;
642 }
643
644 void
645 auth_printsub(data, cnt, buf, buflen)
646 unsigned char *data, *buf;
647 int cnt, buflen;
648 {
649 Authenticator *ap;
650
651 if ((ap = findauthenticator(data[1], data[2])) && ap->printsub)
652 (*ap->printsub)(data, cnt, buf, buflen);
653 else
654 auth_gen_printsub(data, cnt, buf, buflen);
655 }
656
657 void
658 auth_gen_printsub(data, cnt, buf, buflen)
659 unsigned char *data, *buf;
660 int cnt, buflen;
661 {
662 register unsigned char *cp;
663 unsigned char tbuf[16];
664
665 cnt -= 3;
666 data += 3;
667 buf[buflen-1] = '\0';
668 buf[buflen-2] = '*';
669 buflen -= 2;
670 for (; cnt > 0; cnt--, data++) {
671 sprintf((char *)tbuf, " %d", *data);
672 for (cp = tbuf; *cp && buflen > 0; --buflen)
673 *buf++ = *cp++;
674 if (buflen <= 0)
675 return;
676 }
677 *buf = '\0';
678 }
679 #endif
680