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