sra.c revision 85753
1/*- 2 * Copyright (c) 1991, 1993 3 * Dave Safford. 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 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: head/contrib/telnet/libtelnet/sra.c 85690 2001-10-29 16:12:16Z nsayer $"); 33 34#ifdef SRA 35#include <sys/types.h> 36#include <arpa/telnet.h> 37#include <stdio.h> 38#ifdef __STDC__ 39#include <stdlib.h> 40#endif 41#ifdef NO_STRING_H 42#include <strings.h> 43#else 44#include <string.h> 45#endif 46 47#if !defined(NOPAM) 48#include <security/pam_appl.h> 49#else 50#include <unistd.h> 51#endif 52 53#include <pwd.h> 54#include <syslog.h> 55#include <ttyent.h> 56 57#include "auth.h" 58#include "misc.h" 59#include "encrypt.h" 60#include "pk.h" 61 62char pka[HEXKEYBYTES+1], ska[HEXKEYBYTES+1], pkb[HEXKEYBYTES+1]; 63char *user,*pass,*xuser,*xpass; 64DesData ck; 65IdeaData ik; 66 67extern int auth_debug_mode; 68extern char *line; 69 70static int sra_valid = 0; 71static int passwd_sent = 0; 72 73static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, 74 AUTHTYPE_SRA, }; 75 76#define SRA_KEY 0 77#define SRA_USER 1 78#define SRA_CONTINUE 2 79#define SRA_PASS 3 80#define SRA_ACCEPT 4 81#define SRA_REJECT 5 82 83static int check_user(const char *, const char *); 84 85/* support routine to send out authentication message */ 86static int 87Data(Authenticator *ap, int type, void *d, int c) 88{ 89 unsigned char *p = str_data + 4; 90 unsigned char *cd = (unsigned char *)d; 91 92 if (c == -1) 93 c = strlen((char *)cd); 94 95 if (auth_debug_mode) { 96 printf("%s:%d: [%d] (%d)", 97 str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", 98 str_data[3], 99 type, c); 100 printd(d, c); 101 printf("\r\n"); 102 } 103 *p++ = ap->type; 104 *p++ = ap->way; 105 *p++ = type; 106 while (c-- > 0) { 107 if ((*p++ = *cd++) == IAC) 108 *p++ = IAC; 109 } 110 *p++ = IAC; 111 *p++ = SE; 112 if (str_data[3] == TELQUAL_IS) 113 printsub('>', &str_data[2], p - (&str_data[2])); 114 return(net_write(str_data, p - str_data)); 115} 116 117int 118sra_init(Authenticator *ap, int server) 119{ 120 if (server) 121 str_data[3] = TELQUAL_REPLY; 122 else 123 str_data[3] = TELQUAL_IS; 124 125 user = (char *)malloc(256); 126 xuser = (char *)malloc(513); 127 pass = (char *)malloc(256); 128 xpass = (char *)malloc(513); 129 130 if (user == NULL || xuser == NULL || pass == NULL || xpass == 131 NULL) 132 return 0; /* malloc failed */ 133 134 passwd_sent = 0; 135 136 genkeys(pka,ska); 137 return(1); 138} 139 140/* client received a go-ahead for sra */ 141int 142sra_send(Authenticator *ap) 143{ 144 /* send PKA */ 145 146 if (auth_debug_mode) 147 printf("Sent PKA to server.\r\n" ); 148 printf("Trying SRA secure login:\r\n"); 149 if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) { 150 if (auth_debug_mode) 151 printf("Not enough room for authentication data\r\n"); 152 return(0); 153 } 154 155 return(1); 156} 157 158/* server received an IS -- could be SRA KEY, USER, or PASS */ 159void 160sra_is(Authenticator *ap, unsigned char *data, int cnt) 161{ 162 int valid; 163 Session_Key skey; 164 165 if (cnt-- < 1) 166 goto bad; 167 switch (*data++) { 168 169 case SRA_KEY: 170 if (cnt < HEXKEYBYTES) { 171 Data(ap, SRA_REJECT, (void *)0, 0); 172 auth_finished(ap, AUTH_USER); 173 if (auth_debug_mode) { 174 printf("SRA user rejected for bad PKB\r\n"); 175 } 176 return; 177 } 178 if (auth_debug_mode) 179 printf("Sent pka\r\n"); 180 if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) { 181 if (auth_debug_mode) 182 printf("Not enough room\r\n"); 183 return; 184 } 185 memcpy(pkb,data,HEXKEYBYTES); 186 pkb[HEXKEYBYTES] = '\0'; 187 common_key(ska,pkb,&ik,&ck); 188 return; 189 190 case SRA_USER: 191 /* decode KAB(u) */ 192 if (cnt > 512) /* Attempted buffer overflow */ 193 break; 194 memcpy(xuser,data,cnt); 195 xuser[cnt] = '\0'; 196 pk_decode(xuser,user,&ck); 197 auth_encrypt_user(user); 198 Data(ap, SRA_CONTINUE, (void *)0, 0); 199 200 return; 201 202 case SRA_PASS: 203 if (cnt > 512) /* Attempted buffer overflow */ 204 break; 205 /* decode KAB(P) */ 206 memcpy(xpass,data,cnt); 207 xpass[cnt] = '\0'; 208 pk_decode(xpass,pass,&ck); 209 210 /* check user's password */ 211 valid = check_user(user,pass); 212 213 if(valid) { 214 Data(ap, SRA_ACCEPT, (void *)0, 0); 215#ifdef DES_ENCRYPTION 216 skey.data = ck; 217 skey.type = SK_DES; 218 skey.length = 8; 219 encrypt_session_key(&skey, 1); 220#endif 221 222 sra_valid = 1; 223 auth_finished(ap, AUTH_VALID); 224 if (auth_debug_mode) { 225 printf("SRA user accepted\r\n"); 226 } 227 } 228 else { 229 Data(ap, SRA_CONTINUE, (void *)0, 0); 230/* 231 Data(ap, SRA_REJECT, (void *)0, 0); 232 sra_valid = 0; 233 auth_finished(ap, AUTH_REJECT); 234*/ 235 if (auth_debug_mode) { 236 printf("SRA user failed\r\n"); 237 } 238 } 239 return; 240 241 default: 242 if (auth_debug_mode) 243 printf("Unknown SRA option %d\r\n", data[-1]); 244 } 245bad: 246 Data(ap, SRA_REJECT, 0, 0); 247 sra_valid = 0; 248 auth_finished(ap, AUTH_REJECT); 249} 250 251/* client received REPLY -- could be SRA KEY, CONTINUE, ACCEPT, or REJECT */ 252void 253sra_reply(Authenticator *ap, unsigned char *data, int cnt) 254{ 255 extern char *telnet_gets(); 256 char uprompt[256],tuser[256]; 257 Session_Key skey; 258 int i; 259 260 if (cnt-- < 1) 261 return; 262 switch (*data++) { 263 264 case SRA_KEY: 265 /* calculate common key */ 266 if (cnt < HEXKEYBYTES) { 267 if (auth_debug_mode) { 268 printf("SRA user rejected for bad PKB\r\n"); 269 } 270 return; 271 } 272 memcpy(pkb,data,HEXKEYBYTES); 273 pkb[HEXKEYBYTES] = '\0'; 274 275 common_key(ska,pkb,&ik,&ck); 276 277 enc_user: 278 279 /* encode user */ 280 memset(tuser,0,sizeof(tuser)); 281 sprintf(uprompt,"User (%s): ",UserNameRequested); 282 telnet_gets(uprompt,tuser,255,1); 283 if (tuser[0] == '\n' || tuser[0] == '\r' ) 284 strcpy(user,UserNameRequested); 285 else { 286 /* telnet_gets leaves the newline on */ 287 for(i=0;i<sizeof(tuser);i++) { 288 if (tuser[i] == '\n') { 289 tuser[i] = '\0'; 290 break; 291 } 292 } 293 strcpy(user,tuser); 294 } 295 pk_encode(user,xuser,&ck); 296 297 /* send it off */ 298 if (auth_debug_mode) 299 printf("Sent KAB(U)\r\n"); 300 if (!Data(ap, SRA_USER, (void *)xuser, strlen(xuser))) { 301 if (auth_debug_mode) 302 printf("Not enough room\r\n"); 303 return; 304 } 305 break; 306 307 case SRA_CONTINUE: 308 if (passwd_sent) { 309 passwd_sent = 0; 310 printf("[ SRA login failed ]\r\n"); 311 goto enc_user; 312 } 313 /* encode password */ 314 memset(pass,0,sizeof(pass)); 315 telnet_gets("Password: ",pass,255,0); 316 pk_encode(pass,xpass,&ck); 317 /* send it off */ 318 if (auth_debug_mode) 319 printf("Sent KAB(P)\r\n"); 320 if (!Data(ap, SRA_PASS, (void *)xpass, strlen(xpass))) { 321 if (auth_debug_mode) 322 printf("Not enough room\r\n"); 323 return; 324 } 325 passwd_sent = 1; 326 break; 327 328 case SRA_REJECT: 329 printf("[ SRA refuses authentication ]\r\n"); 330 printf("Trying plaintext login:\r\n"); 331 auth_finished(0,AUTH_REJECT); 332 return; 333 334 case SRA_ACCEPT: 335 printf("[ SRA accepts you ]\r\n"); 336#ifdef DES_ENCRYPTION 337 skey.data = ck; 338 skey.type = SK_DES; 339 skey.length = 8; 340 encrypt_session_key(&skey, 0); 341#endif 342 343 auth_finished(ap, AUTH_VALID); 344 return; 345 default: 346 if (auth_debug_mode) 347 printf("Unknown SRA option %d\r\n", data[-1]); 348 return; 349 } 350} 351 352int 353sra_status(Authenticator *ap, char *name, int level) 354{ 355 if (level < AUTH_USER) 356 return(level); 357 if (UserNameRequested && sra_valid) { 358 strcpy(name, UserNameRequested); 359 return(AUTH_VALID); 360 } else 361 return(AUTH_USER); 362} 363 364#define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} 365#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} 366 367void 368sra_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen) 369{ 370 char lbuf[32]; 371 register int i; 372 373 buf[buflen-1] = '\0'; /* make sure its NULL terminated */ 374 buflen -= 1; 375 376 switch(data[3]) { 377 378 case SRA_CONTINUE: 379 strncpy((char *)buf, " CONTINUE ", buflen); 380 goto common; 381 382 case SRA_REJECT: /* Rejected (reason might follow) */ 383 strncpy((char *)buf, " REJECT ", buflen); 384 goto common; 385 386 case SRA_ACCEPT: /* Accepted (name might follow) */ 387 strncpy((char *)buf, " ACCEPT ", buflen); 388 389 common: 390 BUMP(buf, buflen); 391 if (cnt <= 4) 392 break; 393 ADDC(buf, buflen, '"'); 394 for (i = 4; i < cnt; i++) 395 ADDC(buf, buflen, data[i]); 396 ADDC(buf, buflen, '"'); 397 ADDC(buf, buflen, '\0'); 398 break; 399 400 case SRA_KEY: /* Authentication data follows */ 401 strncpy((char *)buf, " KEY ", buflen); 402 goto common2; 403 404 case SRA_USER: 405 strncpy((char *)buf, " USER ", buflen); 406 goto common2; 407 408 case SRA_PASS: 409 strncpy((char *)buf, " PASS ", buflen); 410 goto common2; 411 412 default: 413 sprintf(lbuf, " %d (unknown)", data[3]); 414 strncpy((char *)buf, lbuf, buflen); 415 common2: 416 BUMP(buf, buflen); 417 for (i = 4; i < cnt; i++) { 418 sprintf(lbuf, " %d", data[i]); 419 strncpy((char *)buf, lbuf, buflen); 420 BUMP(buf, buflen); 421 } 422 break; 423 } 424} 425 426struct passwd *pw; 427 428/* 429 * Helper function for sgetpwnam(). 430 */ 431char * 432sgetsave(char *s) 433{ 434 char *new = malloc((unsigned) strlen(s) + 1); 435 436 if (new == NULL) { 437 return(NULL); 438 } 439 (void) strcpy(new, s); 440 return (new); 441} 442 443struct passwd * 444sgetpwnam(char *name) 445{ 446 static struct passwd save; 447 register struct passwd *p; 448 char *sgetsave(); 449 450 if ((p = getpwnam(name)) == NULL) 451 return (p); 452 if (save.pw_name) { 453 free(save.pw_name); 454 free(save.pw_passwd); 455 free(save.pw_gecos); 456 free(save.pw_dir); 457 free(save.pw_shell); 458 } 459 save = *p; 460 save.pw_name = sgetsave(p->pw_name); 461 save.pw_passwd = sgetsave(p->pw_passwd); 462 save.pw_gecos = sgetsave(p->pw_gecos); 463 save.pw_dir = sgetsave(p->pw_dir); 464 save.pw_shell = sgetsave(p->pw_shell); 465#if 0 466syslog(LOG_WARNING,"%s\n",save.pw_name); 467syslog(LOG_WARNING,"%s\n",save.pw_passwd); 468syslog(LOG_WARNING,"%s\n",save.pw_gecos); 469syslog(LOG_WARNING,"%s\n",save.pw_dir); 470#endif 471#ifdef USE_SHADOW 472 { 473 struct spwd *sp; 474 sp = getspnam(name); 475 free(save.pw_passwd); 476 save.pw_passwd = sgetsave(sp->sp_pwdp); 477 } 478#endif 479 return (&save); 480} 481 482static int 483isroot(const char *user) 484{ 485 struct passwd *pw; 486 487 if ((pw=getpwnam(user))==NULL) 488 return 0; 489 return (!pw->pw_uid); 490} 491 492static int 493rootterm(char *ttyn) 494{ 495 struct ttyent *t; 496 497 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 498} 499 500#ifdef NOPAM 501static int 502check_user(const char *name, const char *pass) 503{ 504 register char *cp; 505 char *xpasswd, *salt; 506 507 if (isroot(name) && !rootterm(line)) 508 { 509 crypt("AA","*"); /* Waste some time to simulate success */ 510 return(0); 511 } 512 513 if (pw = sgetpwnam(name)) { 514 if (pw->pw_shell == NULL) { 515 pw = (struct passwd *) NULL; 516 return(0); 517 } 518 519 salt = pw->pw_passwd; 520 xpasswd = crypt(pass, salt); 521 /* The strcmp does not catch null passwords! */ 522 if (pw == NULL || *pw->pw_passwd == '\0' || 523 strcmp(xpasswd, pw->pw_passwd)) { 524 pw = (struct passwd *) NULL; 525 return(0); 526 } 527 return(1); 528 } 529 return(0); 530} 531#else 532 533/* 534 * The following is stolen from ftpd, which stole it from the imap-uw 535 * PAM module and login.c. It is needed because we can't really 536 * "converse" with the user, having already gone to the trouble of 537 * getting their username and password through an encrypted channel. 538 */ 539 540#define COPY_STRING(s) (s ? strdup(s):NULL) 541 542struct cred_t { 543 const char *uname; 544 const char *pass; 545}; 546typedef struct cred_t cred_t; 547 548int 549auth_conv(int num_msg, const struct pam_message **msg, 550 struct pam_response **resp, void *appdata) 551{ 552 int i; 553 cred_t *cred = (cred_t *) appdata; 554 struct pam_response *reply = 555 malloc(sizeof(struct pam_response) * num_msg); 556 557 if (reply == NULL) 558 return PAM_BUF_ERR; 559 560 for (i = 0; i < num_msg; i++) { 561 switch (msg[i]->msg_style) { 562 case PAM_PROMPT_ECHO_ON: /* assume want user name */ 563 reply[i].resp_retcode = PAM_SUCCESS; 564 reply[i].resp = COPY_STRING(cred->uname); 565 /* PAM frees resp. */ 566 break; 567 case PAM_PROMPT_ECHO_OFF: /* assume want password */ 568 reply[i].resp_retcode = PAM_SUCCESS; 569 reply[i].resp = COPY_STRING(cred->pass); 570 /* PAM frees resp. */ 571 break; 572 case PAM_TEXT_INFO: 573 case PAM_ERROR_MSG: 574 reply[i].resp_retcode = PAM_SUCCESS; 575 reply[i].resp = NULL; 576 break; 577 default: /* unknown message style */ 578 free(reply); 579 return PAM_CONV_ERR; 580 } 581 } 582 583 *resp = reply; 584 return PAM_SUCCESS; 585} 586 587/* 588 * The PAM version as a side effect may put a new username in *name. 589 */ 590static int 591check_user(const char *name, const char *pass) 592{ 593 pam_handle_t *pamh = NULL; 594 const void *item; 595 int rval; 596 int e; 597 cred_t auth_cred = { name, pass }; 598 struct pam_conv conv = { &auth_conv, &auth_cred }; 599 600 e = pam_start("telnetd", name, &conv, &pamh); 601 if (e != PAM_SUCCESS) { 602 syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e)); 603 return 0; 604 } 605 606#if 0 /* Where can we find this value? */ 607 e = pam_set_item(pamh, PAM_RHOST, remotehost); 608 if (e != PAM_SUCCESS) { 609 syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s", 610 pam_strerror(pamh, e)); 611 return 0; 612 } 613#endif 614 615 e = pam_authenticate(pamh, 0); 616 switch (e) { 617 case PAM_SUCCESS: 618 /* 619 * With PAM we support the concept of a "template" 620 * user. The user enters a login name which is 621 * authenticated by PAM, usually via a remote service 622 * such as RADIUS or TACACS+. If authentication 623 * succeeds, a different but related "template" name 624 * is used for setting the credentials, shell, and 625 * home directory. The name the user enters need only 626 * exist on the remote authentication server, but the 627 * template name must be present in the local password 628 * database. 629 * 630 * This is supported by two various mechanisms in the 631 * individual modules. However, from the application's 632 * point of view, the template user is always passed 633 * back as a changed value of the PAM_USER item. 634 */ 635 if ((e = pam_get_item(pamh, PAM_USER, &item)) == 636 PAM_SUCCESS) { 637 strcpy((char *) name, (const char *) item); 638 } else 639 syslog(LOG_ERR, "Couldn't get PAM_USER: %s", 640 pam_strerror(pamh, e)); 641 if (isroot(name) && !rootterm(line)) 642 rval = 0; 643 else 644 rval = 1; 645 break; 646 647 case PAM_AUTH_ERR: 648 case PAM_USER_UNKNOWN: 649 case PAM_MAXTRIES: 650 rval = 0; 651 break; 652 653 default: 654 syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e)); 655 rval = 0; 656 break; 657 } 658 659 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) { 660 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); 661 rval = 0; 662 } 663 return rval; 664} 665 666#endif 667 668#endif 669 670