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