1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T 29 * All Rights Reserved. 30 */ 31 32 /* 33 * University Copyright- Copyright (c) 1982, 1986, 1988 34 * The Regents of the University of California. 35 * All Rights Reserved. 36 * 37 * University Acknowledgment- Portions of this document are derived from 38 * software developed by the University of California, Berkeley, and its 39 * contributors. 40 */ 41 42 #pragma ident "%Z%%M% %I% %E% SMI" 43 44 /* 45 * Telnet server. 46 */ 47 #include <sys/types.h> 48 #include <sys/param.h> 49 #include <sys/socket.h> 50 #include <sys/wait.h> 51 #include <sys/file.h> 52 #include <sys/stat.h> 53 #include <sys/filio.h> 54 #include <sys/time.h> 55 #include <sys/stropts.h> 56 #include <sys/stream.h> 57 #include <sys/tihdr.h> 58 #include <sys/utsname.h> 59 #include <unistd.h> 60 61 #include <netinet/in.h> 62 63 #define AUTHWHO_STR 64 #define AUTHTYPE_NAMES 65 #define AUTHHOW_NAMES 66 #define AUTHRSP_NAMES 67 #define ENCRYPT_NAMES 68 69 #include <arpa/telnet.h> 70 #include <arpa/inet.h> 71 #include <stdio.h> 72 #include <stdarg.h> 73 #include <signal.h> 74 #include <errno.h> 75 #include <netdb.h> 76 #include <syslog.h> 77 #include <ctype.h> 78 #include <fcntl.h> 79 #include <sac.h> /* for SC_WILDC */ 80 #include <utmpx.h> 81 #include <sys/ttold.h> 82 #include <malloc.h> 83 #include <string.h> 84 #include <security/pam_appl.h> 85 #include <sys/tihdr.h> 86 #include <sys/logindmux.h> 87 #include <sys/telioctl.h> 88 #include <deflt.h> 89 #include <stdlib.h> 90 #include <string.h> 91 #include <stropts.h> 92 #include <termios.h> 93 94 #include <com_err.h> 95 #include <krb5.h> 96 #include <krb5_repository.h> 97 #include <des/des.h> 98 #include <rpc/des_crypt.h> 99 #include <sys/cryptmod.h> 100 #include <bsm/adt.h> 101 102 #define TELNETD_OPTS "Ss:a:dEXUhR:M:" 103 #ifdef DEBUG 104 #define DEBUG_OPTS "p:e" 105 #else 106 #define DEBUG_OPTS "" 107 #endif /* DEBUG */ 108 109 #define OPT_NO 0 /* won't do this option */ 110 #define OPT_YES 1 /* will do this option */ 111 #define OPT_YES_BUT_ALWAYS_LOOK 2 112 #define OPT_NO_BUT_ALWAYS_LOOK 3 113 114 #define MAXOPTLEN 256 115 #define MAXUSERNAMELEN 256 116 117 static char remopts[MAXOPTLEN]; 118 static char myopts[MAXOPTLEN]; 119 static uchar_t doopt[] = { (uchar_t)IAC, (uchar_t)DO, '%', 'c', 0 }; 120 static uchar_t dont[] = { (uchar_t)IAC, (uchar_t)DONT, '%', 'c', 0 }; 121 static uchar_t will[] = { (uchar_t)IAC, (uchar_t)WILL, '%', 'c', 0 }; 122 static uchar_t wont[] = { (uchar_t)IAC, (uchar_t)WONT, '%', 'c', 0 }; 123 /* 124 * I/O data buffers, pointers, and counters. 125 */ 126 static char ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf; 127 128 static char *netibuf, *netip; 129 static int netibufsize; 130 131 #define NIACCUM(c) { *netip++ = c; \ 132 ncc++; \ 133 } 134 135 static char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; 136 static char *neturg = 0; /* one past last bye of urgent data */ 137 /* the remote system seems to NOT be an old 4.2 */ 138 static int not42 = 1; 139 static char defaultfile[] = "/etc/default/telnetd"; 140 static char bannervar[] = "BANNER="; 141 142 static char BANNER1[] = "\r\n\r\n"; 143 static char BANNER2[] = "\r\n\r\0\r\n\r\0"; 144 145 /* 146 * buffer for sub-options - enlarged to 4096 to handle credentials 147 * from AUTH options 148 */ 149 static char subbuffer[4096], *subpointer = subbuffer, *subend = subbuffer; 150 #define SB_CLEAR() subpointer = subbuffer; 151 #define SB_TERM() { subend = subpointer; SB_CLEAR(); } 152 #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof (subbuffer))) { \ 153 *subpointer++ = (c); \ 154 } 155 #define SB_GET() ((*subpointer++)&0xff) 156 #define SB_EOF() (subpointer >= subend) 157 #define SB_LEN() (subend - subpointer) 158 159 #define MAXERRSTRLEN 1024 160 #define MAXPRINCLEN 256 161 162 extern uint_t kwarn_add_warning(char *, int); 163 extern uint_t kwarn_del_warning(char *); 164 165 static boolean_t auth_debug = 0; 166 static boolean_t negotiate_auth_krb5 = 1; 167 static boolean_t auth_negotiated = 0; 168 static int auth_status = 0; 169 static int auth_level = 0; 170 static char *AuthenticatingUser = NULL; 171 static char *krb5_name = NULL; 172 173 static krb5_address rsaddr = { 0, 0, 0, NULL }; 174 static krb5_address rsport = { 0, 0, 0, NULL }; 175 176 static krb5_context telnet_context = 0; 177 static krb5_auth_context auth_context = 0; 178 179 /* telnetd gets session key from here */ 180 static krb5_ticket *ticket = NULL; 181 static krb5_keyblock *session_key = NULL; 182 static char *telnet_srvtab = NULL; 183 184 typedef struct { 185 uchar_t AuthName; 186 uchar_t AuthHow; 187 char *AuthString; 188 } AuthInfo; 189 190 static AuthInfo auth_list[] = { 191 {AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT | AUTH_HOW_MUTUAL | 192 AUTH_ENCRYPT_ON, "KRB5 MUTUAL CRYPTO"}, 193 {AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT | AUTH_HOW_MUTUAL, 194 "KRB5 MUTUAL" }, 195 {AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT | AUTH_HOW_ONE_WAY, 196 "KRB5 1-WAY" }, 197 {0, 0, "NONE"} 198 }; 199 200 static AuthInfo NoAuth = {0, 0, NULL}; 201 202 static AuthInfo *authenticated = NULL; 203 204 #define PREAMBLE_SIZE 5 /* for auth_reply_str allocation */ 205 #define POSTAMBLE_SIZE 5 206 #define STR_DATA_LEN(len) ((len) * 2 + PREAMBLE_SIZE + POSTAMBLE_SIZE) 207 208 static void auth_name(uchar_t *, int); 209 static void auth_is(uchar_t *, int); 210 211 #define NO_ENCRYPTION 0x00 212 #define SEND_ENCRYPTED 0x01 213 #define RECV_ENCRYPTED 0x02 214 #define ENCRYPT_BOTH_WAYS (SEND_ENCRYPTED | RECV_ENCRYPTED) 215 216 static telnet_enc_data_t encr_data; 217 static boolean_t negotiate_encrypt = B_TRUE; 218 static boolean_t sent_encrypt_support = B_FALSE; 219 static boolean_t sent_will_encrypt = B_FALSE; 220 static boolean_t sent_do_encrypt = B_FALSE; 221 static boolean_t enc_debug = 0; 222 223 static void encrypt_session_key(Session_Key *key, cipher_info_t *cinfo); 224 static int encrypt_send_encrypt_is(); 225 226 extern void mit_des_fixup_key_parity(Block); 227 extern int krb5_setenv(const char *, const char *, int); 228 /* need to know what FD to use to talk to the crypto module */ 229 static int cryptmod_fd = -1; 230 231 #define LOGIN_PROGRAM "/bin/login" 232 233 /* 234 * State for recv fsm 235 */ 236 #define TS_DATA 0 /* base state */ 237 #define TS_IAC 1 /* look for double IAC's */ 238 #define TS_CR 2 /* CR-LF ->'s CR */ 239 #define TS_SB 3 /* throw away begin's... */ 240 #define TS_SE 4 /* ...end's (suboption negotiation) */ 241 #define TS_WILL 5 /* will option negotiation */ 242 #define TS_WONT 6 /* wont " */ 243 #define TS_DO 7 /* do " */ 244 #define TS_DONT 8 /* dont " */ 245 246 static int ncc; 247 static int master; /* master side of pty */ 248 static int pty; /* side of pty that gets ioctls */ 249 static int net; 250 static int inter; 251 extern char **environ; 252 static char *line; 253 static int SYNCHing = 0; /* we are in TELNET SYNCH mode */ 254 static int state = TS_DATA; 255 256 static int env_ovar = -1; /* XXX.sparker */ 257 static int env_ovalue = -1; /* XXX.sparker */ 258 static char pam_svc_name[64]; 259 static boolean_t telmod_init_done = B_FALSE; 260 261 static void doit(int, struct sockaddr_storage *); 262 static void willoption(int); 263 static void wontoption(int); 264 static void dooption(int); 265 static void dontoption(int); 266 static void fatal(int, char *); 267 static void fatalperror(int, char *, int); 268 static void mode(int, int); 269 static void interrupt(void); 270 static void drainstream(int); 271 static int readstream(int, char *, int); 272 static int send_oob(int fd, char *ptr, int count); 273 static int local_setenv(const char *name, const char *value, int rewrite); 274 static void local_unsetenv(const char *name); 275 static void suboption(void); 276 static int removemod(int f, char *modname); 277 static void willoption(int option); 278 static void wontoption(int option); 279 static void dooption(int option); 280 static void dontoption(int option); 281 static void write_data(const char *, ...); 282 static void write_data_len(const char *, int); 283 static void rmut(void); 284 static void cleanup(int); 285 static void telnet(int, int); 286 static void telrcv(void); 287 static void sendbrk(void); 288 static void ptyflush(void); 289 static void netclear(void); 290 static void netflush(void); 291 static void showbanner(void); 292 static void map_banner(char *); 293 static void defbanner(void); 294 static void ttloop(void); 295 296 /* 297 * The env_list linked list is used to store the environment variables 298 * until the final exec of login. A malevolent client might try to 299 * send an environment variable intended to affect the telnet daemon's 300 * execution. Right now the BANNER expansion is the only instance. 301 * Note that it is okay to pass the environment variables to login 302 * because login protects itself against environment variables mischief. 303 */ 304 305 struct envlist { 306 struct envlist *next; 307 char *name; 308 char *value; 309 int delete; 310 }; 311 312 static struct envlist *envlist_head = NULL; 313 314 /* 315 * The following are some clocks used to decide how to interpret 316 * the relationship between various variables. 317 */ 318 319 static struct { 320 int 321 system, /* what the current time is */ 322 echotoggle, /* last time user entered echo character */ 323 modenegotiated, /* last time operating mode negotiated */ 324 didnetreceive, /* last time we read data from network */ 325 ttypeopt, /* ttype will/won't received */ 326 ttypesubopt, /* ttype subopt is received */ 327 getterminal, /* time started to get terminal information */ 328 xdisplocopt, /* xdisploc will/wont received */ 329 xdisplocsubopt, /* xdisploc suboption received */ 330 nawsopt, /* window size will/wont received */ 331 nawssubopt, /* window size received */ 332 environopt, /* environment option will/wont received */ 333 oenvironopt, /* "old" environ option will/wont received */ 334 environsubopt, /* environment option suboption received */ 335 oenvironsubopt, /* "old environ option suboption received */ 336 gotDM; /* when did we last see a data mark */ 337 338 int getauth; 339 int authopt; /* Authentication option negotiated */ 340 int authdone; 341 342 int getencr; 343 int encropt; 344 int encr_support; 345 } clocks; 346 347 static int init_neg_done = 0; 348 static boolean_t resolve_hostname = 0; 349 static boolean_t show_hostinfo = 1; 350 351 #define settimer(x) (clocks.x = ++clocks.system) 352 #define sequenceIs(x, y) (clocks.x < clocks.y) 353 354 static void send_will(int); 355 static void send_wont(int); 356 static void send_do(int); 357 static char *__findenv(const char *name, int *offset); 358 359 /* ARGSUSED */ 360 static void 361 auth_finished(AuthInfo *ap, int result) 362 { 363 if ((authenticated = ap) == NULL) { 364 authenticated = &NoAuth; 365 if (myopts[TELOPT_ENCRYPT] == OPT_YES) 366 send_wont(TELOPT_ENCRYPT); 367 myopts[TELOPT_ENCRYPT] = remopts[TELOPT_ENCRYPT] = OPT_NO; 368 encr_data.encrypt.autoflag = 0; 369 } else if (result != AUTH_REJECT && 370 myopts[TELOPT_ENCRYPT] == OPT_YES && 371 remopts[TELOPT_ENCRYPT] == OPT_YES) { 372 373 /* 374 * Authentication successful, so we have a session key, and 375 * we're willing to do ENCRYPT, so send our ENCRYPT SUPPORT. 376 * 377 * Can't have sent ENCRYPT SUPPORT yet! And if we're sending it 378 * now it's really only because we did the DO ENCRYPT/WILL 379 * ENCRYPT dance before authentication, which is ok, but not too 380 * bright since we have to do the DONT ENCRYPT/WONT ENCRYPT 381 * dance if authentication fails, though clients typically just 382 * don't care. 383 */ 384 write_data("%c%c%c%c%c%c%c", 385 (uchar_t)IAC, 386 (uchar_t)SB, 387 (uchar_t)TELOPT_ENCRYPT, 388 (uchar_t)ENCRYPT_SUPPORT, 389 (uchar_t)TELOPT_ENCTYPE_DES_CFB64, 390 (uchar_t)IAC, 391 (uchar_t)SE); 392 393 netflush(); 394 395 sent_encrypt_support = B_TRUE; 396 397 if (enc_debug) 398 (void) fprintf(stderr, 399 "SENT ENCRYPT SUPPORT\n"); 400 401 (void) encrypt_send_encrypt_is(); 402 } 403 404 auth_status = result; 405 406 settimer(authdone); 407 } 408 409 static void 410 reply_to_client(AuthInfo *ap, int type, void *data, int len) 411 { 412 uchar_t reply[BUFSIZ]; 413 uchar_t *p = reply; 414 uchar_t *cd = (uchar_t *)data; 415 416 if (len == -1 && data != NULL) 417 len = strlen((char *)data); 418 else if (len > (sizeof (reply) - 9)) { 419 syslog(LOG_ERR, 420 "krb5 auth reply length too large (%d)", len); 421 if (auth_debug) 422 (void) fprintf(stderr, 423 "krb5 auth reply length too large (%d)\n", 424 len); 425 return; 426 } else if (data == NULL) 427 len = 0; 428 429 *p++ = IAC; 430 *p++ = SB; 431 *p++ = TELOPT_AUTHENTICATION; 432 *p++ = AUTHTYPE_KERBEROS_V5; 433 *p++ = ap->AuthName; 434 *p++ = ap->AuthHow; /* MUTUAL, ONE-WAY, etc */ 435 *p++ = type; /* RESPONSE or ACCEPT */ 436 while (len-- > 0) { 437 if ((*p++ = *cd++) == IAC) 438 *p++ = IAC; 439 } 440 *p++ = IAC; 441 *p++ = SE; 442 443 /* queue the data to be sent */ 444 write_data_len((const char *)reply, p-reply); 445 446 #if defined(AUTHTYPE_NAMES) && defined(AUTHWHO_STR) &&\ 447 defined(AUTHHOW_NAMES) && defined(AUTHRSP_NAMES) 448 if (auth_debug) { 449 (void) fprintf(stderr, "SENT TELOPT_AUTHENTICATION REPLY " 450 "%s %s|%s %s\n", 451 AUTHTYPE_NAME(ap->AuthName), 452 AUTHWHO_NAME(ap->AuthHow & AUTH_WHO_MASK), 453 AUTHHOW_NAME(ap->AuthHow & AUTH_HOW_MASK), 454 AUTHRSP_NAME(type)); 455 } 456 #endif /* AUTHTYPE_NAMES && AUTHWHO_NAMES && AUTHHOW_NAMES && AUTHRSP_NAMES */ 457 458 netflush(); 459 } 460 461 /* Decode, decrypt and store the forwarded creds in the local ccache. */ 462 static krb5_error_code 463 rd_and_store_forwarded_creds(krb5_context context, 464 krb5_auth_context auth_context, 465 krb5_data *inbuf, krb5_ticket *ticket, 466 char *username) 467 { 468 krb5_creds **creds; 469 krb5_error_code retval; 470 char ccname[MAXPATHLEN]; 471 krb5_ccache ccache = NULL; 472 char *client_name = NULL; 473 474 if (retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)) 475 return (retval); 476 477 (void) sprintf(ccname, "FILE:/tmp/krb5cc_p%ld", getpid()); 478 (void) krb5_setenv("KRB5CCNAME", ccname, 1); 479 480 if ((retval = krb5_cc_default(context, &ccache))) 481 goto cleanup; 482 483 if ((retval = krb5_cc_initialize(context, ccache, 484 ticket->enc_part2->client)) != 0) 485 goto cleanup; 486 487 if ((retval = krb5_cc_store_cred(context, ccache, *creds)) != 0) 488 goto cleanup; 489 490 if ((retval = krb5_cc_close(context, ccache)) != 0) 491 goto cleanup; 492 493 /* Register with ktkt_warnd(1M) */ 494 if ((retval = krb5_unparse_name(context, (*creds)->client, 495 &client_name)) != 0) 496 goto cleanup; 497 (void) kwarn_del_warning(client_name); 498 if (kwarn_add_warning(client_name, (*creds)->times.endtime) != 0) { 499 syslog(LOG_AUTH|LOG_NOTICE, 500 "rd_and_store_forwarded_creds: kwarn_add_warning" 501 " failed: ktkt_warnd(1M) down? "); 502 if (auth_debug) 503 (void) fprintf(stderr, 504 "kwarn_add_warning failed:" 505 " ktkt_warnd(1M) down?\n"); 506 } 507 free(client_name); 508 client_name = NULL; 509 510 if (username != NULL) { 511 /* 512 * This verifies that the user is valid on the local system, 513 * maps the username from KerberosV5 to unix, 514 * and moves the KRB5CCNAME file to the correct place 515 * /tmp/krb5cc_[uid] with correct ownership (0600 uid gid). 516 * 517 * NOTE: the user must be in the gsscred table in order to map 518 * from KRB5 to Unix. 519 */ 520 (void) krb5_kuserok(context, ticket->enc_part2->client, 521 username); 522 } 523 if (auth_debug) 524 (void) fprintf(stderr, 525 "Successfully stored forwarded creds\n"); 526 527 cleanup: 528 krb5_free_creds(context, *creds); 529 return (retval); 530 } 531 532 static void 533 kerberos5_is(AuthInfo *ap, uchar_t *data, int cnt) 534 { 535 krb5_error_code err = 0; 536 krb5_principal server; 537 krb5_keyblock *newkey = NULL; 538 krb5_keytab keytabid = 0; 539 krb5_data outbuf; 540 krb5_data inbuf; 541 krb5_authenticator *authenticator; 542 char errbuf[MAXERRSTRLEN]; 543 char *name; 544 krb5_data auth; 545 546 Session_Key skey; 547 548 if (cnt-- < 1) 549 return; 550 switch (*data++) { 551 case KRB_AUTH: 552 auth.data = (char *)data; 553 auth.length = cnt; 554 555 if (auth_context == NULL) { 556 err = krb5_auth_con_init(telnet_context, &auth_context); 557 if (err) 558 syslog(LOG_ERR, 559 "Error getting krb5 auth " 560 "context: %s", error_message(err)); 561 } 562 if (!err) { 563 krb5_rcache rcache; 564 565 err = krb5_auth_con_getrcache(telnet_context, 566 auth_context, 567 &rcache); 568 if (!err && !rcache) { 569 err = krb5_sname_to_principal(telnet_context, 570 0, 0, 571 KRB5_NT_SRV_HST, 572 &server); 573 if (!err) { 574 err = krb5_get_server_rcache( 575 telnet_context, 576 krb5_princ_component( 577 telnet_context, 578 server, 0), 579 &rcache); 580 581 krb5_free_principal(telnet_context, 582 server); 583 } 584 } 585 if (err) 586 syslog(LOG_ERR, 587 "Error allocating krb5 replay cache: %s", 588 error_message(err)); 589 else { 590 err = krb5_auth_con_setrcache(telnet_context, 591 auth_context, 592 rcache); 593 if (err) 594 syslog(LOG_ERR, 595 "Error creating krb5 " 596 "replay cache: %s", 597 error_message(err)); 598 } 599 } 600 if (!err && telnet_srvtab != NULL) 601 err = krb5_kt_resolve(telnet_context, 602 telnet_srvtab, &keytabid); 603 if (!err) 604 err = krb5_rd_req(telnet_context, &auth_context, &auth, 605 NULL, keytabid, NULL, &ticket); 606 if (err) { 607 (void) snprintf(errbuf, sizeof (errbuf), 608 "Error reading krb5 auth information:" 609 " %s", error_message(err)); 610 goto errout; 611 } 612 613 /* 614 * Verify that the correct principal was used 615 */ 616 if (krb5_princ_component(telnet_context, 617 ticket->server, 0)->length < MAXPRINCLEN) { 618 char princ[MAXPRINCLEN]; 619 (void) strncpy(princ, 620 krb5_princ_component(telnet_context, 621 ticket->server, 0)->data, 622 krb5_princ_component(telnet_context, 623 ticket->server, 0)->length); 624 princ[krb5_princ_component(telnet_context, 625 ticket->server, 0)->length] = '\0'; 626 if (strcmp("host", princ)) { 627 if (strlen(princ) < sizeof (errbuf) - 39) { 628 (void) snprintf(errbuf, sizeof (errbuf), 629 "incorrect service " 630 "name: \"%s\" != " 631 "\"host\"", 632 princ); 633 } else { 634 (void) strncpy(errbuf, 635 "incorrect service " 636 "name: principal != " 637 "\"host\"", 638 sizeof (errbuf)); 639 } 640 goto errout; 641 } 642 } else { 643 (void) strlcpy(errbuf, "service name too long", 644 sizeof (errbuf)); 645 goto errout; 646 } 647 648 err = krb5_auth_con_getauthenticator(telnet_context, 649 auth_context, 650 &authenticator); 651 if (err) { 652 (void) snprintf(errbuf, sizeof (errbuf), 653 "Failed to get authenticator: %s", 654 error_message(err)); 655 goto errout; 656 } 657 if ((ap->AuthHow & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON && 658 !authenticator->checksum) { 659 (void) strlcpy(errbuf, 660 "authenticator is missing checksum", 661 sizeof (errbuf)); 662 goto errout; 663 } 664 if (authenticator->checksum) { 665 char type_check[2]; 666 krb5_checksum *cksum = authenticator->checksum; 667 krb5_keyblock *key; 668 krb5_data input; 669 krb5_boolean valid; 670 671 type_check[0] = ap->AuthName; 672 type_check[1] = ap->AuthHow; 673 674 err = krb5_auth_con_getkey(telnet_context, 675 auth_context, &key); 676 if (err) { 677 (void) snprintf(errbuf, sizeof (errbuf), 678 "Failed to get key from " 679 "authenticator: %s", 680 error_message(err)); 681 goto errout; 682 } 683 684 input.data = type_check; 685 input.length = 2; 686 err = krb5_c_verify_checksum(telnet_context, 687 key, 0, 688 &input, 689 cksum, 690 &valid); 691 if (!err && !valid) 692 err = KRB5KRB_AP_ERR_BAD_INTEGRITY; 693 694 if (err) { 695 (void) snprintf(errbuf, sizeof (errbuf), 696 "Kerberos checksum " 697 "verification failed: " 698 "%s", 699 error_message(err)); 700 goto errout; 701 } 702 krb5_free_keyblock(telnet_context, key); 703 } 704 705 krb5_free_authenticator(telnet_context, authenticator); 706 if ((ap->AuthHow & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 707 /* do ap_rep stuff here */ 708 if ((err = krb5_mk_rep(telnet_context, auth_context, 709 &outbuf))) { 710 (void) snprintf(errbuf, sizeof (errbuf), 711 "Failed to make " 712 "Kerberos auth reply: " 713 "%s", 714 error_message(err)); 715 goto errout; 716 } 717 reply_to_client(ap, KRB_RESPONSE, outbuf.data, 718 outbuf.length); 719 } 720 if (krb5_unparse_name(telnet_context, 721 ticket->enc_part2->client, 722 &name)) 723 name = 0; 724 reply_to_client(ap, KRB_ACCEPT, name, name ? -1 : 0); 725 if (auth_debug) { 726 syslog(LOG_NOTICE, 727 "\tKerberos5 identifies user as ``%s''\r\n", 728 name ? name : ""); 729 } 730 if (name != NULL) { 731 krb5_name = (char *)strdup(name); 732 } 733 auth_finished(ap, AUTH_USER); 734 735 if (name != NULL) 736 free(name); 737 krb5_auth_con_getremotesubkey(telnet_context, auth_context, 738 &newkey); 739 if (session_key != NULL) { 740 krb5_free_keyblock(telnet_context, session_key); 741 session_key = 0; 742 } 743 if (newkey != NULL) { 744 krb5_copy_keyblock(telnet_context, 745 newkey, &session_key); 746 krb5_free_keyblock(telnet_context, newkey); 747 } else { 748 krb5_copy_keyblock(telnet_context, 749 ticket->enc_part2->session, 750 &session_key); 751 } 752 753 /* 754 * Initialize encryption stuff. Currently, we are only 755 * supporting 8 byte keys and blocks. Check for this later. 756 */ 757 skey.type = SK_DES; 758 skey.length = DES_BLOCKSIZE; 759 skey.data = session_key->contents; 760 encrypt_session_key(&skey, &encr_data.encrypt); 761 encrypt_session_key(&skey, &encr_data.decrypt); 762 break; 763 case KRB_FORWARD: 764 inbuf.length = cnt; 765 inbuf.data = (char *)data; 766 if (auth_debug) 767 (void) fprintf(stderr, 768 "RCVD KRB_FORWARD data (%d bytes)\n", cnt); 769 770 if (auth_context != NULL) { 771 krb5_rcache rcache; 772 773 err = krb5_auth_con_getrcache(telnet_context, 774 auth_context, &rcache); 775 if (!err && !rcache) { 776 err = krb5_sname_to_principal(telnet_context, 777 0, 0, KRB5_NT_SRV_HST, &server); 778 if (!err) { 779 err = krb5_get_server_rcache( 780 telnet_context, 781 krb5_princ_component( 782 telnet_context, 783 server, 0), 784 &rcache); 785 krb5_free_principal(telnet_context, 786 server); 787 } 788 } 789 if (err) { 790 syslog(LOG_ERR, 791 "Error allocating krb5 replay cache: %s", 792 error_message(err)); 793 } else { 794 err = krb5_auth_con_setrcache(telnet_context, 795 auth_context, rcache); 796 if (err) 797 syslog(LOG_ERR, 798 "Error creating krb5 replay cache:" 799 " %s", 800 error_message(err)); 801 } 802 } 803 /* 804 * Use the 'rsaddr' and 'rsport' (remote service addr/port) 805 * from the original connection. This data is used to 806 * verify the forwarded credentials. 807 */ 808 if (!(err = krb5_auth_con_setaddrs(telnet_context, auth_context, 809 NULL, &rsaddr))) 810 err = krb5_auth_con_setports(telnet_context, 811 auth_context, NULL, &rsport); 812 813 if (err == 0) 814 /* 815 * If all is well, store the forwarded creds in 816 * the users local credential cache. 817 */ 818 err = rd_and_store_forwarded_creds(telnet_context, 819 auth_context, &inbuf, 820 ticket, 821 AuthenticatingUser); 822 if (err) { 823 (void) snprintf(errbuf, sizeof (errbuf), 824 "Read forwarded creds failed: %s", 825 error_message(err)); 826 syslog(LOG_ERR, "%s", errbuf); 827 828 reply_to_client(ap, KRB_FORWARD_REJECT, errbuf, -1); 829 if (auth_debug) 830 (void) fprintf(stderr, 831 "\tCould not read " 832 "forwarded credentials\r\n"); 833 } else 834 reply_to_client(ap, KRB_FORWARD_ACCEPT, (void *) 0, 0); 835 836 if (rsaddr.contents != NULL) 837 free(rsaddr.contents); 838 839 if (rsport.contents != NULL) 840 free(rsport.contents); 841 842 if (auth_debug) 843 (void) fprintf(stderr, "\tForwarded " 844 "credentials obtained\r\n"); 845 break; 846 default: 847 if (auth_debug) 848 (void) fprintf(stderr, 849 "\tUnknown Kerberos option %d\r\n", 850 data[-1]); 851 reply_to_client(ap, KRB_REJECT, (void *) 0, 0); 852 break; 853 } 854 return; 855 856 errout: 857 reply_to_client(ap, KRB_REJECT, errbuf, -1); 858 859 if (auth_debug) 860 (void) fprintf(stderr, "\tKerberos V5 error: %s\r\n", errbuf); 861 862 syslog(LOG_ERR, "%s", errbuf); 863 864 if (auth_context != NULL) { 865 krb5_auth_con_free(telnet_context, auth_context); 866 auth_context = 0; 867 } 868 } 869 870 static int 871 krb5_init() 872 { 873 int code = 0; 874 875 if (telnet_context == NULL) { 876 code = krb5_init_context(&telnet_context); 877 if (code != 0 && auth_debug) 878 syslog(LOG_NOTICE, 879 "Cannot initialize Kerberos V5: %s", 880 error_message(code)); 881 } 882 883 return (code); 884 } 885 886 static void 887 auth_name(uchar_t *data, int cnt) 888 { 889 char namebuf[MAXPRINCLEN]; 890 891 if (cnt < 1) { 892 if (auth_debug) 893 (void) fprintf(stderr, 894 "\t(auth_name) Empty NAME in auth " 895 "reply\n"); 896 return; 897 } 898 if (cnt > sizeof (namebuf)-1) { 899 if (auth_debug) 900 (void) fprintf(stderr, 901 "\t(auth_name) NAME exceeds %d bytes\n", 902 sizeof (namebuf)-1); 903 return; 904 } 905 (void) memcpy((void *)namebuf, (void *)data, cnt); 906 namebuf[cnt] = 0; 907 if (auth_debug) 908 (void) fprintf(stderr, "\t(auth_name) name [%s]\n", namebuf); 909 AuthenticatingUser = (char *)strdup(namebuf); 910 } 911 912 static void 913 auth_is(uchar_t *data, int cnt) 914 { 915 AuthInfo *aptr = auth_list; 916 917 if (cnt < 2) 918 return; 919 920 /* 921 * We failed to negoiate secure authentication 922 */ 923 if (data[0] == AUTHTYPE_NULL) { 924 auth_finished(0, AUTH_REJECT); 925 return; 926 } 927 928 while (aptr->AuthName != NULL && 929 (aptr->AuthName != data[0] || aptr->AuthHow != data[1])) 930 aptr++; 931 932 if (aptr != NULL) { 933 if (auth_debug) 934 (void) fprintf(stderr, "\t(auth_is) auth type is %s " 935 "(%d bytes)\n", aptr->AuthString, cnt); 936 937 if (aptr->AuthName == AUTHTYPE_KERBEROS_V5) 938 kerberos5_is(aptr, data+2, cnt-2); 939 } 940 } 941 942 static int 943 krb5_user_status(char *name, int namelen, int level) 944 { 945 int retval = AUTH_USER; 946 947 if (auth_debug) 948 (void) fprintf(stderr, "\t(krb5_user_status) level = %d " 949 "auth_level = %d user = %s\n", 950 level, auth_level, 951 (AuthenticatingUser != NULL ? AuthenticatingUser : "")); 952 953 if (level < AUTH_USER) 954 return (level); 955 956 if (AuthenticatingUser != NULL && 957 (retval = krb5_kuserok(telnet_context, ticket->enc_part2->client, 958 AuthenticatingUser))) { 959 (void) strncpy(name, AuthenticatingUser, namelen); 960 return (AUTH_VALID); 961 } else { 962 if (!retval) 963 syslog(LOG_ERR, 964 "Krb5 principal lacks permission to " 965 "access local account for %s", 966 AuthenticatingUser); 967 return (AUTH_USER); 968 } 969 } 970 971 /* 972 * Wrapper around /dev/urandom 973 */ 974 static int 975 getrandom(char *buf, int buflen) 976 { 977 static int devrandom = -1; 978 979 if (devrandom == -1 && 980 (devrandom = open("/dev/urandom", O_RDONLY)) == -1) { 981 fatalperror(net, "Unable to open /dev/urandom: ", 982 errno); 983 return (-1); 984 } 985 986 if (read(devrandom, buf, buflen) == -1) { 987 fatalperror(net, "Unable to read from /dev/urandom: ", 988 errno); 989 return (-1); 990 } 991 992 return (0); 993 } 994 995 /* 996 * encrypt_init 997 * 998 * Initialize the encryption data structures 999 */ 1000 static void 1001 encrypt_init() 1002 { 1003 (void) memset(&encr_data.encrypt, 0, sizeof (cipher_info_t)); 1004 (void) memset(&encr_data.decrypt, 0, sizeof (cipher_info_t)); 1005 1006 encr_data.encrypt.state = ENCR_STATE_NOT_READY; 1007 encr_data.decrypt.state = ENCR_STATE_NOT_READY; 1008 } <