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