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