Annotation of src/usr.bin/telnet/auth.c, Revision 1.2
1.2 ! deraadt 1: /* $OpenBSD: auth.c,v 1.1 2005/05/24 03:43:56 deraadt Exp $ */
1.1 deraadt 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. Neither the name of the University nor the names of its contributors
16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
32: /*
33: * This source code is no longer held under any constraint of USA
34: * `cryptographic laws' since it was exported legally. The cryptographic
35: * functions were removed from the code and a "Bones" distribution was
36: * made. A Commodity Jurisdiction Request #012-94 was filed with the
37: * USA State Department, who handed it to the Commerce department. The
38: * code was determined to fall under General License GTDA under ECCN 5D96G,
39: * and hence exportable. The cryptographic interfaces were re-added by Eric
40: * Young, and then KTH proceeded to maintain the code in the free world.
41: *
42: */
43:
44: /*
45: * Copyright (C) 1990 by the Massachusetts Institute of Technology
46: *
47: * Export of this software from the United States of America is assumed
48: * to require a specific license from the United States Government.
49: * It is the responsibility of any person or organization contemplating
50: * export to obtain such a license before exporting.
51: *
52: * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
53: * distribute this software and its documentation for any purpose and
54: * without fee is hereby granted, provided that the above copyright
55: * notice appear in all copies and that both that copyright notice and
56: * this permission notice appear in supporting documentation, and that
57: * the name of M.I.T. not be used in advertising or publicity pertaining
58: * to distribution of the software without specific, written prior
59: * permission. M.I.T. makes no representations about the suitability of
60: * this software for any purpose. It is provided "as is" without express
61: * or implied warranty.
62: */
63:
64: /* "$KTH: auth.c,v 1.23 2000/01/18 03:09:34 assar Exp $" */
65:
66: #if defined(AUTHENTICATION)
67: #include <stdio.h>
68: #include <sys/types.h>
69: #include <unistd.h>
70: #include <signal.h>
71: #define AUTH_NAMES
72: #include <arpa/telnet.h>
73: #include <stdlib.h>
74: #include <string.h>
75:
76: #include "encrypt.h"
77: #include "auth.h"
78: #include "misc-proto.h"
79: #include "auth-proto.h"
80:
81: #define typemask(x) (1<<((x)-1))
82:
83: #ifdef KRB4_ENCPWD
84: extern krb4encpwd_init();
85: extern krb4encpwd_send();
86: extern krb4encpwd_is();
87: extern krb4encpwd_reply();
88: extern krb4encpwd_status();
89: extern krb4encpwd_printsub();
90: #endif
91:
92: #ifdef RSA_ENCPWD
93: extern rsaencpwd_init();
94: extern rsaencpwd_send();
95: extern rsaencpwd_is();
96: extern rsaencpwd_reply();
97: extern rsaencpwd_status();
98: extern rsaencpwd_printsub();
99: #endif
100:
101: int auth_debug_mode = 0;
102: int auth_has_failed = 0;
103: int auth_enable_encrypt = 0;
104: static const char *Name = "Noname";
105: static int Server = 0;
106: static Authenticator *authenticated = 0;
107: static int authenticating = 0;
108: static int validuser = 0;
109: static unsigned char _auth_send_data[256];
110: static unsigned char *auth_send_data;
111: static int auth_send_cnt = 0;
112:
113: /*
114: * Authentication types supported. Plese note that these are stored
115: * in priority order, i.e. try the first one first.
116: */
117: Authenticator authenticators[] = {
118: #ifdef UNSAFE
119: { AUTHTYPE_UNSAFE, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
120: unsafe_init,
121: unsafe_send,
122: unsafe_is,
123: unsafe_reply,
124: unsafe_status,
125: unsafe_printsub },
126: #endif
127: #ifdef SRA
128: { AUTHTYPE_SRA, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
129: sra_init,
130: sra_send,
131: sra_is,
132: sra_reply,
133: sra_status,
134: sra_printsub },
135: #endif
136: #ifdef SPX
137: { AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
138: spx_init,
139: spx_send,
140: spx_is,
141: spx_reply,
142: spx_status,
143: spx_printsub },
144: { AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
145: spx_init,
146: spx_send,
147: spx_is,
148: spx_reply,
149: spx_status,
150: spx_printsub },
151: #endif
152: #ifdef KRB5
153: { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
154: kerberos5_init,
155: kerberos5_send_mutual,
156: kerberos5_is,
157: kerberos5_reply,
158: kerberos5_status,
159: kerberos5_printsub },
160: { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
161: kerberos5_init,
162: kerberos5_send_oneway,
163: kerberos5_is,
164: kerberos5_reply,
165: kerberos5_status,
166: kerberos5_printsub },
167: #endif
168: #ifdef KRB4
169: { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
170: kerberos4_init,
171: kerberos4_send_mutual,
172: kerberos4_is,
173: kerberos4_reply,
174: kerberos4_status,
175: kerberos4_printsub },
176: { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
177: kerberos4_init,
178: kerberos4_send_oneway,
179: kerberos4_is,
180: kerberos4_reply,
181: kerberos4_status,
182: kerberos4_printsub },
183: #endif
184: #ifdef KRB4_ENCPWD
185: { AUTHTYPE_KRB4_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
186: krb4encpwd_init,
187: krb4encpwd_send,
188: krb4encpwd_is,
189: krb4encpwd_reply,
190: krb4encpwd_status,
191: krb4encpwd_printsub },
192: #endif
193: #ifdef RSA_ENCPWD
194: { AUTHTYPE_RSA_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
195: rsaencpwd_init,
196: rsaencpwd_send,
197: rsaencpwd_is,
198: rsaencpwd_reply,
199: rsaencpwd_status,
200: rsaencpwd_printsub },
201: #endif
202: { 0, },
203: };
204:
205: static Authenticator NoAuth = { 0 };
206:
207: static int i_support = 0;
208: static int i_wont_support = 0;
209:
210: Authenticator *
211: findauthenticator(int type, int way)
212: {
213: Authenticator *ap = authenticators;
214:
215: while (ap->type && (ap->type != type || ap->way != way))
216: ++ap;
217: return(ap->type ? ap : 0);
218: }
219:
220: void
221: auth_init(const char *name, int server)
222: {
223: Authenticator *ap = authenticators;
224:
225: Server = server;
226: Name = name;
227:
228: i_support = 0;
229: authenticated = 0;
230: authenticating = 0;
231: while (ap->type) {
232: if (!ap->init || (*ap->init)(ap, server)) {
233: i_support |= typemask(ap->type);
234: if (auth_debug_mode)
235: printf(">>>%s: I support auth type %d %d\r\n",
236: Name,
237: ap->type, ap->way);
238: }
239: else if (auth_debug_mode)
240: printf(">>>%s: Init failed: auth type %d %d\r\n",
241: Name, ap->type, ap->way);
242: ++ap;
243: }
244: }
245:
246: void
247: auth_disable_name(char *name)
248: {
249: int x;
250: for (x = 0; x < AUTHTYPE_CNT; ++x) {
251: if (!strcasecmp(name, AUTHTYPE_NAME(x))) {
252: i_wont_support |= typemask(x);
253: break;
254: }
255: }
256: }
257:
258: int
259: getauthmask(char *type, int *maskp)
260: {
261: int x;
262:
263: if (!strcasecmp(type, AUTHTYPE_NAME(0))) {
264: *maskp = -1;
265: return(1);
266: }
267:
268: for (x = 1; x < AUTHTYPE_CNT; ++x) {
269: if (!strcasecmp(type, AUTHTYPE_NAME(x))) {
270: *maskp = typemask(x);
271: return(1);
272: }
273: }
274: return(0);
275: }
276:
277: int
278: auth_enable(char *type)
279: {
280: return(auth_onoff(type, 1));
281: }
282:
283: int
284: auth_disable(char *type)
285: {
286: return(auth_onoff(type, 0));
287: }
288:
289: int
290: auth_onoff(char *type, int on)
291: {
292: int i, mask = -1;
293: Authenticator *ap;
294:
295: if (!strcasecmp(type, "?") || !strcasecmp(type, "help")) {
296: printf("auth %s 'type'\n", on ? "enable" : "disable");
297: printf("Where 'type' is one of:\n");
298: printf("\t%s\n", AUTHTYPE_NAME(0));
299: mask = 0;
300: for (ap = authenticators; ap->type; ap++) {
301: if ((mask & (i = typemask(ap->type))) != 0)
302: continue;
303: mask |= i;
304: printf("\t%s\n", AUTHTYPE_NAME(ap->type));
305: }
306: return(0);
307: }
308:
309: if (!getauthmask(type, &mask)) {
310: printf("%s: invalid authentication type\n", type);
311: return(0);
312: }
313: if (on)
314: i_wont_support &= ~mask;
315: else
316: i_wont_support |= mask;
317: return(1);
318: }
319:
320: int
321: auth_togdebug(int on)
322: {
323: if (on < 0)
324: auth_debug_mode ^= 1;
325: else
326: auth_debug_mode = on;
327: printf("auth debugging %s\n", auth_debug_mode ? "enabled" : "disabled");
328: return(1);
329: }
330:
331: int
332: auth_status(void)
333: {
334: Authenticator *ap;
335: int i, mask;
336:
337: if (i_wont_support == -1)
338: printf("Authentication disabled\n");
339: else
340: printf("Authentication enabled\n");
341:
342: mask = 0;
343: for (ap = authenticators; ap->type; ap++) {
344: if ((mask & (i = typemask(ap->type))) != 0)
345: continue;
346: mask |= i;
347: printf("%s: %s\n", AUTHTYPE_NAME(ap->type),
348: (i_wont_support & typemask(ap->type)) ?
349: "disabled" : "enabled");
350: }
351: return(1);
352: }
353:
354: /*
355: * This routine is called by the server to start authentication
356: * negotiation.
357: */
358: void
359: auth_request(void)
360: {
361: static unsigned char str_request[64] = { IAC, SB,
362: TELOPT_AUTHENTICATION,
363: TELQUAL_SEND, };
364: Authenticator *ap = authenticators;
365: unsigned char *e = str_request + 4;
366:
367: if (!authenticating) {
368: authenticating = 1;
369: while (ap->type) {
370: if (i_support & ~i_wont_support & typemask(ap->type)) {
371: if (auth_debug_mode) {
372: printf(">>>%s: Sending type %d %d\r\n",
373: Name, ap->type, ap->way);
374: }
375: *e++ = ap->type;
376: *e++ = ap->way;
377: }
378: ++ap;
379: }
380: *e++ = IAC;
381: *e++ = SE;
382: telnet_net_write(str_request, e - str_request);
383: printsub('>', &str_request[2], e - str_request - 2);
384: }
385: }
386:
387: /*
388: * This is called when an AUTH SEND is received.
389: * It should never arrive on the server side (as only the server can
390: * send an AUTH SEND).
391: * You should probably respond to it if you can...
392: *
393: * If you want to respond to the types out of order (i.e. even
394: * if he sends LOGIN KERBEROS and you support both, you respond
395: * with KERBEROS instead of LOGIN (which is against what the
396: * protocol says)) you will have to hack this code...
397: */
398: void
399: auth_send(unsigned char *data, int cnt)
400: {
401: Authenticator *ap;
402: static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION,
403: TELQUAL_IS, AUTHTYPE_NULL, 0,
404: IAC, SE };
405: if (Server) {
406: if (auth_debug_mode) {
407: printf(">>>%s: auth_send called!\r\n", Name);
408: }
409: return;
410: }
411:
412: if (auth_debug_mode) {
413: printf(">>>%s: auth_send got:", Name);
414: printd(data, cnt); printf("\r\n");
415: }
416:
417: /*
418: * Save the data, if it is new, so that we can continue looking
419: * at it if the authorization we try doesn't work
420: */
421: if (data < _auth_send_data ||
422: data > _auth_send_data + sizeof(_auth_send_data)) {
423: auth_send_cnt = cnt > sizeof(_auth_send_data)
424: ? sizeof(_auth_send_data)
425: : cnt;
426: memmove(_auth_send_data, data, auth_send_cnt);
427: auth_send_data = _auth_send_data;
428: } else {
429: /*
430: * This is probably a no-op, but we just make sure
431: */
432: auth_send_data = data;
433: auth_send_cnt = cnt;
434: }
435: while ((auth_send_cnt -= 2) >= 0) {
436: if (auth_debug_mode)
437: printf(">>>%s: He supports %d\r\n",
438: Name, *auth_send_data);
439: if ((i_support & ~i_wont_support) & typemask(*auth_send_data)) {
440: ap = findauthenticator(auth_send_data[0],
441: auth_send_data[1]);
442: if (ap && ap->send) {
443: if (auth_debug_mode)
444: printf(">>>%s: Trying %d %d\r\n",
445: Name, auth_send_data[0],
446: auth_send_data[1]);
447: if ((*ap->send)(ap)) {
448: /*
449: * Okay, we found one we like
450: * and did it.
451: * we can go home now.
452: */
453: if (auth_debug_mode)
454: printf(">>>%s: Using type %d\r\n",
455: Name, *auth_send_data);
456: auth_send_data += 2;
457: return;
458: }
459: }
460: /* else
461: * just continue on and look for the
462: * next one if we didn't do anything.
463: */
464: }
465: auth_send_data += 2;
466: }
467: telnet_net_write(str_none, sizeof(str_none));
468: printsub('>', &str_none[2], sizeof(str_none) - 2);
469: if (auth_debug_mode)
470: printf(">>>%s: Sent failure message\r\n", Name);
471: auth_finished(0, AUTH_REJECT);
472: auth_has_failed = 1;
473: #ifdef KANNAN
474: /*
475: * We requested strong authentication, however no mechanisms worked.
476: * Therefore, exit on client end.
477: */
478: printf("Unable to securely authenticate user ... exit\n");
479: exit(0);
480: #endif /* KANNAN */
481: }
482:
483: void
484: auth_send_retry(void)
485: {
486: /*
487: * if auth_send_cnt <= 0 then auth_send will end up rejecting
488: * the authentication and informing the other side of this.
489: */
490: auth_send(auth_send_data, auth_send_cnt);
491: }
492:
493: void
494: auth_is(unsigned char *data, int cnt)
495: {
496: Authenticator *ap;
497:
498: if (cnt < 2)
499: return;
500:
501: if (data[0] == AUTHTYPE_NULL) {
502: auth_finished(0, AUTH_REJECT);
503: return;
504: }
505:
506: if ((ap = findauthenticator(data[0], data[1]))) {
507: if (ap->is)
508: (*ap->is)(ap, data+2, cnt-2);
509: } else if (auth_debug_mode)
510: printf(">>>%s: Invalid authentication in IS: %d\r\n",
511: Name, *data);
512: }
513:
514: void
515: auth_reply(unsigned char *data, int cnt)
516: {
517: Authenticator *ap;
518:
519: if (cnt < 2)
520: return;
521:
522: if ((ap = findauthenticator(data[0], data[1]))) {
523: if (ap->reply)
524: (*ap->reply)(ap, data+2, cnt-2);
525: } else if (auth_debug_mode)
526: printf(">>>%s: Invalid authentication in SEND: %d\r\n",
527: Name, *data);
528: }
529:
530: void
531: auth_name(unsigned char *data, int cnt)
532: {
533: char savename[256];
534:
535: if (cnt < 1) {
536: if (auth_debug_mode)
537: printf(">>>%s: Empty name in NAME\r\n", Name);
538: return;
539: }
540: if (cnt > sizeof(savename) - 1) {
541: if (auth_debug_mode)
542: printf(">>>%s: Name in NAME (%d) exceeds %lu length\r\n",
543: Name, cnt, (unsigned long)(sizeof(savename)-1));
544: return;
545: }
546: memmove(savename, data, cnt);
547: savename[cnt] = '\0'; /* Null terminate */
548: if (auth_debug_mode)
549: printf(">>>%s: Got NAME [%s]\r\n", Name, savename);
550: auth_encrypt_user(savename);
551: }
552:
553: int
554: auth_sendname(unsigned char *cp, int len)
555: {
556: static unsigned char str_request[256+6]
557: = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, };
558: unsigned char *e = str_request + 4;
559: unsigned char *ee = &str_request[sizeof(str_request)-2];
560:
561: while (--len >= 0) {
562: if ((*e++ = *cp++) == IAC)
563: *e++ = IAC;
564: if (e >= ee)
565: return(0);
566: }
567: *e++ = IAC;
568: *e++ = SE;
569: telnet_net_write(str_request, e - str_request);
570: printsub('>', &str_request[2], e - &str_request[2]);
571: return(1);
572: }
573:
574: void
575: auth_finished(Authenticator *ap, int result)
576: {
577: if (!(authenticated = ap))
578: authenticated = &NoAuth;
579: validuser = result;
580: }
581:
582: /* ARGSUSED */
583: static void
584: auth_intr(int sig)
585: {
586: auth_finished(0, AUTH_REJECT);
587: }
588:
589: int
590: auth_wait(char *name, size_t name_sz)
591: {
592: if (auth_debug_mode)
593: printf(">>>%s: in auth_wait.\r\n", Name);
594:
595: if (Server && !authenticating)
596: return(0);
597:
598: signal(SIGALRM, auth_intr);
599: alarm(30);
600: while (!authenticated)
601: if (telnet_spin())
602: break;
603: alarm(0);
604: signal(SIGALRM, SIG_DFL);
605:
606: /*
607: * Now check to see if the user is valid or not
608: */
609: if (!authenticated || authenticated == &NoAuth)
610: return(AUTH_REJECT);
611:
612: if (validuser == AUTH_VALID)
613: validuser = AUTH_USER;
614:
615: if (authenticated->status)
616: validuser = (*authenticated->status)(authenticated,
617: name, name_sz,
618: validuser);
619: return(validuser);
620: }
621:
622: void
623: auth_debug(int mode)
624: {
625: auth_debug_mode = mode;
626: }
627:
628: void
629: auth_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
630: {
631: Authenticator *ap;
632:
633: if ((ap = findauthenticator(data[1], data[2])) && ap->printsub)
634: (*ap->printsub)(data, cnt, buf, buflen);
635: else
636: auth_gen_printsub(data, cnt, buf, buflen);
637: }
638:
639: void
640: auth_gen_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
641: {
642: unsigned char *cp;
643: unsigned char tbuf[16];
644:
645: cnt -= 3;
646: data += 3;
647: buf[buflen-1] = '\0';
648: buf[buflen-2] = '*';
649: buflen -= 2;
650: for (; cnt > 0; cnt--, data++) {
651: snprintf(tbuf, sizeof(tbuf), " %d", *data);
652: for (cp = tbuf; *cp && buflen > 0; --buflen)
653: *buf++ = *cp++;
654: if (buflen <= 0)
655: return;
656: }
657: *buf = '\0';
658: }
659: #endif