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