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