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 619