Merge branches 'hammer2' and 'master' of ssh://crater.dragonflybsd.org/repository...
[dragonfly.git] / lib / 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  * $FreeBSD: src/crypto/telnet/libtelnet/auth.c,v 1.3.2.5 2002/04/13 10:59:07 markm Exp $
34  *
35  * @(#)auth.c   8.3 (Berkeley) 5/30/95
36  * $FreeBSD: src/crypto/telnet/libtelnet/auth.c,v 1.3.2.5 2002/04/13 10:59:07 markm Exp $
37  */
38
39 /*
40  * Copyright (C) 1990 by the Massachusetts Institute of Technology
41  *
42  * Export of this software from the United States of America is assumed
43  * to require a specific license from the United States Government.
44  * It is the responsibility of any person or organization contemplating
45  * export to obtain such a license before exporting.
46  *
47  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
48  * distribute this software and its documentation for any purpose and
49  * without fee is hereby granted, provided that the above copyright
50  * notice appear in all copies and that both that copyright notice and
51  * this permission notice appear in supporting documentation, and that
52  * the name of M.I.T. not be used in advertising or publicity pertaining
53  * to distribution of the software without specific, written prior
54  * permission.  M.I.T. makes no representations about the suitability of
55  * this software for any purpose.  It is provided "as is" without express
56  * or implied warranty.
57  */
58
59
60 #ifdef  AUTHENTICATION
61 #define AUTH_NAMES
62 #include <sys/types.h>
63 #include <signal.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <unistd.h>
68 #include <arpa/telnet.h>
69
70 #include "encrypt.h"
71 #include "auth.h"
72 #include "misc-proto.h"
73 #include "auth-proto.h"
74
75 #define typemask(x)     ((x) > 0 ? 1 << ((x)-1) : 0)
76
77 #ifdef  KRB4_ENCPWD
78 extern krb4encpwd_init();
79 extern krb4encpwd_send();
80 extern krb4encpwd_is();
81 extern krb4encpwd_reply();
82 extern krb4encpwd_status();
83 extern krb4encpwd_printsub();
84 #endif
85
86 #ifdef  RSA_ENCPWD
87 extern rsaencpwd_init();
88 extern rsaencpwd_send();
89 extern rsaencpwd_is();
90 extern rsaencpwd_reply();
91 extern rsaencpwd_status();
92 extern rsaencpwd_printsub();
93 #endif
94
95 int auth_debug_mode = 0;
96 static  const char      *Name = "Noname";
97 static  int     Server = 0;
98 static  Authenticator   *authenticated = NULL;
99 static  int     authenticating = 0;
100 static  int     validuser = 0;
101 static  unsigned char   _auth_send_data[256];
102 static  unsigned char   *auth_send_data;
103 static  int     auth_send_cnt = 0;
104
105 int auth_onoff(char *type, int on);
106 void auth_encrypt_user(char *name);
107
108 /*
109  * Authentication types supported.  Plese note that these are stored
110  * in priority order, i.e. try the first one first.
111  */
112 Authenticator authenticators[] = {
113 #ifdef  KRB5
114 # ifdef ENCRYPTION
115         { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
116                                 kerberos5_init,
117                                 kerberos5_send_mutual,
118                                 kerberos5_is,
119                                 kerberos5_reply,
120                                 kerberos5_status,
121                                 kerberos5_printsub },
122 # endif /* ENCRYPTION */
123         { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
124                                 kerberos5_init,
125                                 kerberos5_send_oneway,
126                                 kerberos5_is,
127                                 kerberos5_reply,
128                                 kerberos5_status,
129                                 kerberos5_printsub },
130 #endif
131 #ifdef  KRB4
132 # ifdef ENCRYPTION
133         { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
134                                 kerberos4_init,
135                                 kerberos4_send,
136                                 kerberos4_is,
137                                 kerberos4_reply,
138                                 kerberos4_status,
139                                 kerberos4_printsub },
140 # endif /* ENCRYPTION */
141         { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
142                                 kerberos4_init,
143                                 kerberos4_send,
144                                 kerberos4_is,
145                                 kerberos4_reply,
146                                 kerberos4_status,
147                                 kerberos4_printsub },
148 #endif
149 #ifdef  KRB4_ENCPWD
150         { AUTHTYPE_KRB4_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
151                                 krb4encpwd_init,
152                                 krb4encpwd_send,
153                                 krb4encpwd_is,
154                                 krb4encpwd_reply,
155                                 krb4encpwd_status,
156                                 krb4encpwd_printsub },
157 #endif
158 #ifdef  RSA_ENCPWD
159         { AUTHTYPE_RSA_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
160                                 rsaencpwd_init,
161                                 rsaencpwd_send,
162                                 rsaencpwd_is,
163                                 rsaencpwd_reply,
164                                 rsaencpwd_status,
165                                 rsaencpwd_printsub },
166 #endif
167 #ifdef SRA
168         { AUTHTYPE_SRA, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
169                                 sra_init,
170                                 sra_send,
171                                 sra_is,
172                                 sra_reply,
173                                 sra_status,
174                                 sra_printsub },
175
176 #endif
177         { 0, 0, 0, 0, 0, 0, 0, 0 },
178 };
179
180 static Authenticator NoAuth = { 0, 0, 0, 0, 0, 0, 0, 0 };
181
182 static int      i_support = 0;
183 static int      i_wont_support = 0;
184
185 Authenticator *
186 findauthenticator(int type, int way)
187 {
188         Authenticator *ap = authenticators;
189
190         while (ap->type && (ap->type != type || ap->way != way))
191                 ++ap;
192         return(ap->type ? ap : 0);
193 }
194
195 void
196 auth_init(const char *name, int server)
197 {
198         Authenticator *ap = authenticators;
199
200         Server = server;
201         Name = name;
202
203         i_support = 0;
204         authenticated = NULL;
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(char *name)
223 {
224         int x;
225         for (x = 0; x < AUTHTYPE_CNT; ++x) {
226                 if (AUTHTYPE_NAME(x) && !strcasecmp(name, AUTHTYPE_NAME(x))) {
227                         i_wont_support |= typemask(x);
228                         break;
229                 }
230         }
231 }
232
233 int
234 getauthmask(char *type, int *maskp)
235 {
236         int x;
237
238         if (AUTHTYPE_NAME(0) && !strcasecmp(type, AUTHTYPE_NAME(0))) {
239                 *maskp = -1;
240                 return(1);
241         }
242
243         for (x = 1; x < AUTHTYPE_CNT; ++x) {
244                 if (AUTHTYPE_NAME(x) && !strcasecmp(type, AUTHTYPE_NAME(x))) {
245                         *maskp = typemask(x);
246                         return(1);
247                 }
248         }
249         return(0);
250 }
251
252 int
253 auth_enable(char *type)
254 {
255         return(auth_onoff(type, 1));
256 }
257
258 int
259 auth_disable(char *type)
260 {
261         return(auth_onoff(type, 0));
262 }
263
264 int
265 auth_onoff(char *type, int on)
266 {
267         int i, mask = -1;
268         Authenticator *ap;
269
270         if (!strcasecmp(type, "?") || !strcasecmp(type, "help")) {
271                 printf("auth %s 'type'\n", on ? "enable" : "disable");
272                 printf("Where 'type' is one of:\n");
273                 printf("\t%s\n", AUTHTYPE_NAME(0));
274                 mask = 0;
275                 for (ap = authenticators; ap->type; ap++) {
276                         if ((mask & (i = typemask(ap->type))) != 0)
277                                 continue;
278                         mask |= i;
279                         printf("\t%s\n", AUTHTYPE_NAME(ap->type));
280                 }
281                 return(0);
282         }
283
284         if (!getauthmask(type, &mask)) {
285                 printf("%s: invalid authentication type\n", type);
286                 return(0);
287         }
288         if (on)
289                 i_wont_support &= ~mask;
290         else
291                 i_wont_support |= mask;
292         return(1);
293 }
294
295 int
296 auth_togdebug(int on)
297 {
298         if (on < 0)
299                 auth_debug_mode ^= 1;
300         else
301                 auth_debug_mode = on;
302         printf("auth debugging %s\n", auth_debug_mode ? "enabled" : "disabled");
303         return(1);
304 }
305
306 int
307 auth_status(void)
308 {
309         Authenticator *ap;
310         int i, mask;
311
312         if (i_wont_support == -1)
313                 printf("Authentication disabled\n");
314         else
315                 printf("Authentication enabled\n");
316
317         mask = 0;
318         for (ap = authenticators; ap->type; ap++) {
319                 if ((mask & (i = typemask(ap->type))) != 0)
320                         continue;
321                 mask |= i;
322                 printf("%s: %s\n", AUTHTYPE_NAME(ap->type),
323                         (i_wont_support & typemask(ap->type)) ?
324                                         "disabled" : "enabled");
325         }
326         return(1);
327 }
328
329 /*
330  * This routine is called by the server to start authentication
331  * negotiation.
332  */
333 void
334 auth_request(void)
335 {
336         static unsigned char str_request[64] = { IAC, SB,
337                                                  TELOPT_AUTHENTICATION,
338                                                  TELQUAL_SEND, };
339         Authenticator *ap = authenticators;
340         unsigned char *e = str_request + 4;
341
342         if (!authenticating) {
343                 authenticating = 1;
344                 while (ap->type) {
345                         if (i_support & ~i_wont_support & typemask(ap->type)) {
346                                 if (auth_debug_mode) {
347                                         printf(">>>%s: Sending type %d %d\r\n",
348                                                 Name, ap->type, ap->way);
349                                 }
350                                 *e++ = ap->type;
351                                 *e++ = ap->way;
352                         }
353                         ++ap;
354                 }
355                 *e++ = IAC;
356                 *e++ = SE;
357                 net_write(str_request, e - str_request);
358                 printsub('>', &str_request[2], e - str_request - 2);
359         }
360 }
361
362 /*
363  * This is called when an AUTH SEND is received.
364  * It should never arrive on the server side (as only the server can
365  * send an AUTH SEND).
366  * You should probably respond to it if you can...
367  *
368  * If you want to respond to the types out of order (i.e. even
369  * if he sends  LOGIN KERBEROS and you support both, you respond
370  * with KERBEROS instead of LOGIN (which is against what the
371  * protocol says)) you will have to hack this code...
372  */
373 void
374 auth_send(unsigned char *data, int cnt)
375 {
376         Authenticator *ap;
377         static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION,
378                                             TELQUAL_IS, AUTHTYPE_NULL, 0,
379                                             IAC, SE };
380         if (Server) {
381                 if (auth_debug_mode) {
382                         printf(">>>%s: auth_send called!\r\n", Name);
383                 }
384                 return;
385         }
386
387         if (auth_debug_mode) {
388                 printf(">>>%s: auth_send got:", Name);
389                 printd(data, cnt); printf("\r\n");
390         }
391
392         /*
393          * Save the data, if it is new, so that we can continue looking
394          * at it if the authorization we try doesn't work
395          */
396         if (data < _auth_send_data ||
397             data > _auth_send_data + sizeof(_auth_send_data)) {
398                 auth_send_cnt = (size_t)cnt > sizeof(_auth_send_data)
399                                         ? sizeof(_auth_send_data)
400                                         : cnt;
401                 memmove((void *)_auth_send_data, (void *)data, auth_send_cnt);
402                 auth_send_data = _auth_send_data;
403         } else {
404                 /*
405                  * This is probably a no-op, but we just make sure
406                  */
407                 auth_send_data = data;
408                 auth_send_cnt = cnt;
409         }
410         while ((auth_send_cnt -= 2) >= 0) {
411                 if (auth_debug_mode)
412                         printf(">>>%s: He supports %d\r\n",
413                                 Name, *auth_send_data);
414                 if ((i_support & ~i_wont_support) & typemask(*auth_send_data)) {
415                         ap = findauthenticator(auth_send_data[0],
416                                                auth_send_data[1]);
417                         if (ap && ap->send) {
418                                 if (auth_debug_mode)
419                                         printf(">>>%s: Trying %d %d\r\n",
420                                                 Name, auth_send_data[0],
421                                                         auth_send_data[1]);
422                                 if ((*ap->send)(ap)) {
423                                         /*
424                                          * Okay, we found one we like
425                                          * and did it.
426                                          * we can go home now.
427                                          */
428                                         if (auth_debug_mode)
429                                                 printf(">>>%s: Using type %d\r\n",
430                                                         Name, *auth_send_data);
431                                         auth_send_data += 2;
432                                         return;
433                                 }
434                         }
435                         /* else
436                          *      just continue on and look for the
437                          *      next one if we didn't do anything.
438                          */
439                 }
440                 auth_send_data += 2;
441         }
442         net_write(str_none, sizeof(str_none));
443         printsub('>', &str_none[2], sizeof(str_none) - 2);
444         if (auth_debug_mode)
445                 printf(">>>%s: Sent failure message\r\n", Name);
446         auth_finished(0, AUTH_REJECT);
447 }
448
449 void
450 auth_send_retry(void)
451 {
452         /*
453          * if auth_send_cnt <= 0 then auth_send will end up rejecting
454          * the authentication and informing the other side of this.
455          */
456         auth_send(auth_send_data, auth_send_cnt);
457 }
458
459 void
460 auth_is(unsigned char *data, int cnt)
461 {
462         Authenticator *ap;
463
464         if (cnt < 2)
465                 return;
466
467         if (data[0] == AUTHTYPE_NULL) {
468                 auth_finished(0, AUTH_REJECT);
469                 return;
470         }
471
472         if ((ap = findauthenticator(data[0], data[1]))) {
473                 if (ap->is)
474                         (*ap->is)(ap, data+2, cnt-2);
475         } else if (auth_debug_mode)
476                 printf(">>>%s: Invalid authentication in IS: %d\r\n",
477                         Name, *data);
478 }
479
480 void
481 auth_reply(unsigned char *data, int cnt)
482 {
483         Authenticator *ap;
484
485         if (cnt < 2)
486                 return;
487
488         if ((ap = findauthenticator(data[0], data[1]))) {
489                 if (ap->reply)
490                         (*ap->reply)(ap, data+2, cnt-2);
491         } else if (auth_debug_mode)
492                 printf(">>>%s: Invalid authentication in SEND: %d\r\n",
493                         Name, *data);
494 }
495
496 void
497 auth_name(unsigned char *data, int cnt)
498 {
499         unsigned char savename[256];
500
501         if (cnt < 1) {
502                 if (auth_debug_mode)
503                         printf(">>>%s: Empty name in NAME\r\n", Name);
504                 return;
505         }
506         if ((size_t)cnt > sizeof(savename) - 1) {
507                 if (auth_debug_mode)
508                         printf(">>>%s: Name in NAME (%d) exceeds %d length\r\n",
509                                         Name, cnt, (u_int)sizeof(savename)-1);
510                 return;
511         }
512         memmove((void *)savename, (void *)data, cnt);
513         savename[cnt] = '\0';   /* Null terminate */
514         if (auth_debug_mode)
515                 printf(">>>%s: Got NAME [%s]\r\n", Name, savename);
516         auth_encrypt_user(savename);
517 }
518
519 int
520 auth_sendname(unsigned char *cp, int len)
521 {
522         static unsigned char str_request[256+6]
523                         = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, };
524         unsigned char *e = str_request + 4;
525         unsigned char *ee = &str_request[sizeof(str_request)-2];
526
527         while (--len >= 0) {
528                 if ((*e++ = *cp++) == IAC)
529                         *e++ = IAC;
530                 if (e >= ee)
531                         return(0);
532         }
533         *e++ = IAC;
534         *e++ = SE;
535         net_write(str_request, e - str_request);
536         printsub('>', &str_request[2], e - &str_request[2]);
537         return(1);
538 }
539
540 void
541 auth_finished(Authenticator *ap, int result)
542 {
543         if (!(authenticated = ap))
544                 authenticated = &NoAuth;
545         validuser = result;
546 }
547
548 /* ARGSUSED */
549 static void
550 auth_intr(int sig __unused)
551 {
552         auth_finished(0, AUTH_REJECT);
553 }
554
555 int
556 auth_wait(char *name)
557 {
558         if (auth_debug_mode)
559                 printf(">>>%s: in auth_wait.\r\n", Name);
560
561         if (Server && !authenticating)
562                 return(0);
563
564         (void) signal(SIGALRM, auth_intr);
565         alarm(30);
566         while (!authenticated)
567                 if (telnet_spin())
568                         break;
569         alarm(0);
570         (void) signal(SIGALRM, SIG_DFL);
571
572         /*
573          * Now check to see if the user is valid or not
574          */
575         if (!authenticated || authenticated == &NoAuth)
576                 return(AUTH_REJECT);
577
578         if (validuser == AUTH_VALID)
579                 validuser = AUTH_USER;
580
581         if (authenticated->status)
582                 validuser = (*authenticated->status)(authenticated,
583                                                      name, validuser);
584         return(validuser);
585 }
586
587 void
588 auth_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
589 {
590         Authenticator *ap;
591
592         if ((ap = findauthenticator(data[1], data[2])) && ap->printsub)
593                 (*ap->printsub)(data, cnt, buf, buflen);
594         else
595                 auth_gen_printsub(data, cnt, buf, buflen);
596 }
597
598 void
599 auth_gen_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
600 {
601         unsigned char *cp;
602         unsigned char tbuf[16];
603
604         cnt -= 3;
605         data += 3;
606         buf[buflen-1] = '\0';
607         buf[buflen-2] = '*';
608         buflen -= 2;
609         for (; cnt > 0; cnt--, data++) {
610                 sprintf((char *)tbuf, " %d", *data);
611                 for (cp = tbuf; *cp && buflen > 0; --buflen)
612                         *buf++ = *cp++;
613                 if (buflen <= 0)
614                         return;
615         }
616         *buf = '\0';
617 }
618 #endif