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