1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright(c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1983 The Regents of the University of California. 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms are permitted 14 * provided that the above copyright notice and this paragraph are 15 * duplicated in all such forms and that any documentation, 16 * advertising materials, and other materials related to such 17 * distribution and use acknowledge that the software was developed 18 * by the University of California, Berkeley. The name of the 19 * University may not be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 23 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * remote login server: 30 * remuser\0 31 * locuser\0 32 * terminal info\0 33 * data 34 */ 35 36 #include <time.h> 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <sys/socket.h> 40 #include <sys/wait.h> 41 42 #include <netinet/in.h> 43 44 #include <errno.h> 45 #include <signal.h> 46 #include <fcntl.h> 47 #include <stdio.h> 48 #include <netdb.h> 49 #include <syslog.h> 50 #include <string.h> 51 #include <unistd.h> 52 #include <stdlib.h> 53 #include <alloca.h> 54 #include <stropts.h> 55 #include <sac.h> /* for SC_WILDC */ 56 #include <utmpx.h> 57 #include <sys/filio.h> 58 #include <sys/logindmux.h> 59 #include <sys/rlioctl.h> 60 #include <sys/termios.h> 61 #include <sys/tihdr.h> 62 #include <arpa/inet.h> 63 #include <security/pam_appl.h> 64 #include <strings.h> 65 #include <com_err.h> 66 #include <k5-int.h> 67 #include <kcmd.h> 68 #include <krb5_repository.h> 69 #include <sys/cryptmod.h> 70 #include <bsm/adt.h> 71 #include <addr_match.h> 72 #include <store_forw_creds.h> 73 74 #define KRB5_RECVAUTH_V5 5 75 #define UT_NAMESIZE sizeof (((struct utmpx *)0)->ut_name) 76 77 static char lusername[UT_NAMESIZE+1]; 78 static char rusername[UT_NAMESIZE+1]; 79 static char *krusername = NULL; 80 static char term[64]; 81 82 static krb5_ccache ccache = NULL; 83 static krb5_keyblock *session_key = NULL; 84 static int chksum_flag = 0; 85 static int use_auth = 0; 86 static enum kcmd_proto kcmd_protocol; 87 #ifdef ALLOW_KCMD_V2 88 static krb5_data encr_iv = { NULL, 0 }; 89 static krb5_data decr_iv = { NULL, 0 }; 90 #endif /* ALLOW_KCMD_V2 */ 91 92 #define CHKSUM_REQUIRED 0x01 93 #define CHKSUM_IGNORED 0x02 94 #define VALID_CHKSUM(x) ((x) == 0 || (x) == CHKSUM_REQUIRED ||\ 95 (x) == CHKSUM_IGNORED) 96 97 #define PWD_IF_FAIL 0x01 98 #define PWD_REQUIRED 0x02 99 100 #define AUTH_NONE 0x00 101 102 #define ARGSTR "k5exEXciM:s:S:D:" 103 #define DEFAULT_TOS 16 104 105 #define KRB5_PROG_NAME "krlogin" 106 107 #define SECURE_MSG "This rlogin session is using encryption " \ 108 "for all data transmissions.\r\n" 109 110 #define KRB_V5_SENDAUTH_VERS "KRB5_SENDAUTH_V1.0" 111 #define KRB5_RECVAUTH_V5 5 112 113 static krb5_error_code krb5_compat_recvauth(krb5_context context, 114 krb5_auth_context *auth_context, 115 krb5_pointer fdp, 116 krb5_principal server, 117 krb5_int32 flags, 118 krb5_keytab keytab, 119 krb5_ticket **ticket, 120 krb5_int32 *auth_sys, 121 krb5_data *version); 122 123 static void do_krb_login(int, char *, char *, krb5_context, int, krb5_keytab); 124 static int configure_stream(int, krb5_keyblock *, int, krb5_data *, uint_t); 125 126 extern krb5_error_code krb5_read_message(krb5_context, krb5_pointer, 127 krb5_data *); 128 extern krb5_error_code krb5_net_read(krb5_context, int, char *, int); 129 130 #define LOGIN_PROGRAM "/bin/login" 131 132 #define DEFAULT_PROG_NAME "rlogin" 133 134 static const char *pam_prog_name = DEFAULT_PROG_NAME; 135 static void rmut(void); 136 static void doit(int, struct sockaddr_storage *, krb5_context, int, 137 krb5_keytab); 138 static void protocol(int, int, int); 139 140 static int readstream(int, char *, int); 141 static void fatal(int, const char *); 142 static void fatalperror(int, const char *); 143 static int send_oob(int fd, void *ptr, size_t count); 144 static int removemod(int f, char *modname); 145 146 static int 147 issock(int fd) 148 { 149 struct stat stats; 150 151 if (fstat(fd, &stats) == -1) 152 return (0); 153 return (S_ISSOCK(stats.st_mode)); 154 } 155 156 /* 157 * audit_rlogin_settid stores the terminal id while it is still 158 * available. Subsequent calls to adt_load_hostname() return 159 * the id which is stored here. 160 */ 161 static int 162 audit_rlogin_settid(int fd) { 163 adt_session_data_t *ah; 164 adt_termid_t *termid; 165 int rc; 166 167 if ((rc = adt_start_session(&ah, NULL, 0)) == 0) { 168 if ((rc = adt_load_termid(fd, &termid)) == 0) { 169 if ((rc = adt_set_user(ah, ADT_NO_AUDIT, 170 ADT_NO_AUDIT, 0, ADT_NO_AUDIT, 171 termid, ADT_SETTID)) == 0) 172 (void) adt_set_proc(ah); 173 free(termid); 174 } 175 (void) adt_end_session(ah); 176 } 177 return (rc); 178 } 179 180 181 /* ARGSUSED */ 182 int 183 main(int argc, char *argv[]) 184 { 185 int on = 1; 186 socklen_t fromlen; 187 struct sockaddr_storage from; 188 int fd = -1; 189 190 extern char *optarg; 191 char c; 192 int tos = -1; 193 krb5_context krb_context; 194 krb5_keytab keytab = NULL; 195 krb5_error_code status; 196 char *realm = NULL; 197 char *keytab_file = NULL; 198 int encr_flag = 0; 199 struct sockaddr_storage ouraddr; 200 socklen_t ourlen; 201 #ifdef DEBUG 202 int debug_port = 0; 203 #endif /* DEBUG */ 204 openlog("rlogind", LOG_PID | LOG_ODELAY, LOG_DAEMON); 205 206 while ((c = getopt(argc, argv, ARGSTR)) != -1) { 207 switch (c) { 208 case 'k': 209 case '5': 210 use_auth = KRB5_RECVAUTH_V5; 211 break; 212 case 'e': 213 case 'E': 214 case 'x': 215 case 'X': 216 encr_flag = 1; 217 break; 218 case 'M': 219 realm = (char *)strdup(optarg); 220 break; 221 case 'S': 222 keytab_file = (char *)strdup(optarg); 223 break; 224 case 'c': 225 chksum_flag |= CHKSUM_REQUIRED; 226 break; 227 case 'i': 228 chksum_flag |= CHKSUM_IGNORED; 229 break; 230 case 's': 231 if (optarg == NULL || (tos = atoi(optarg)) < 0 || 232 tos > 255) { 233 syslog(LOG_ERR, "%s: illegal tos value: " 234 "%s\n", argv[0], optarg); 235 } else { 236 if (tos < 0) 237 tos = DEFAULT_TOS; 238 } 239 break; 240 #ifdef DEBUG 241 case 'D': 242 debug_port = atoi(optarg); 243 break; 244 #endif /* DEBUG */ 245 default: 246 syslog(LOG_ERR, "Unrecognized command line option " 247 "(%s), exiting", argv[optind]); 248 exit(EXIT_FAILURE); 249 } 250 } 251 if (use_auth == KRB5_RECVAUTH_V5) { 252 status = krb5_init_context(&krb_context); 253 if (status) { 254 syslog(LOG_ERR, "Error initializing krb5: %s", 255 error_message(status)); 256 exit(EXIT_FAILURE); 257 } 258 if (realm != NULL) 259 krb5_set_default_realm(krb_context, realm); 260 if (keytab_file != NULL) { 261 if ((status = krb5_kt_resolve(krb_context, 262 keytab_file, 263 &keytab))) { 264 com_err(argv[0], 265 status, 266 "while resolving srvtab file %s", 267 keytab_file); 268 exit(EXIT_FAILURE); 269 } 270 } 271 } 272 273 #ifdef DEBUG 274 if (debug_port) { 275 int s; 276 struct sockaddr_in sin; 277 278 if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) { 279 fatalperror(STDERR_FILENO, "Error in socket"); 280 } 281 282 (void) memset((char *)&sin, 0, sizeof (sin)); 283 sin.sin_family = AF_INET; 284 sin.sin_port = htons(debug_port); 285 sin.sin_addr.s_addr = INADDR_ANY; 286 287 (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 288 (char *)&on, sizeof (on)); 289 290 if ((bind(s, (struct sockaddr *)&sin, sizeof (sin))) < 0) { 291 fatalperror(STDERR_FILENO, "bind error"); 292 } 293 294 if ((listen(s, 5)) < 0) { 295 fatalperror(STDERR_FILENO, "listen error"); 296 } 297 298 fromlen = sizeof (from); 299 if ((fd = accept(s, (struct sockaddr *)&from, &fromlen)) < 0) { 300 fatalperror(STDERR_FILENO, "accept error"); 301 } 302 303 (void) close(s); 304 } else 305 #endif /* DEBUG */ 306 { 307 if (!issock(STDIN_FILENO)) 308 fatal(STDIN_FILENO, 309 "stdin is not a socket file descriptor"); 310 fd = STDIN_FILENO; 311 } 312 313 fromlen = sizeof (from); 314 if (getpeername(fd, (struct sockaddr *)&from, &fromlen) < 0) 315 fatalperror(STDERR_FILENO, "getpeername"); 316 317 if (audit_rlogin_settid(fd)) /* set terminal ID */ 318 fatalperror(STDERR_FILENO, "audit"); 319 320 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 321 sizeof (on)) < 0) 322 syslog(LOG_WARNING, "setsockopt(SO_KEEPALIVE): %m"); 323 324 if (!VALID_CHKSUM(chksum_flag)) { 325 syslog(LOG_ERR, "Configuration error: mutually exclusive " 326 "options specified (-c and -i)"); 327 fatal(fd, "Checksums are required and ignored (-c and -i);" 328 "these options are mutually exclusive - check " 329 "the documentation."); 330 } 331 ourlen = sizeof (ouraddr); 332 if (getsockname(fd, (struct sockaddr *)&ouraddr, &ourlen) == -1) { 333 syslog(LOG_ERR, "getsockname error: %m"); 334 exit(EXIT_FAILURE); 335 } 336 337 if (tos != -1 && 338 ouraddr.ss_family != AF_INET6 && 339 setsockopt(fd, IPPROTO_IP, IP_TOS, (char *)&tos, 340 sizeof (tos)) < 0 && 341 errno != ENOPROTOOPT) { 342 syslog(LOG_ERR, "setsockopt(IP_TOS %d): %m", tos); 343 } 344 doit(fd, &from, krb_context, encr_flag, keytab); 345 return (0); 346 } 347 348 static void cleanup(int); 349 static int nsize = 0; /* bytes read prior to pushing rlmod */ 350 static char *rlbuf; /* buffer where nbytes are read to */ 351 static char *line; 352 353 static struct winsize win = { 0, 0, 0, 0 }; 354 static pid_t pid; 355 static char hostname[MAXHOSTNAMELEN + 1]; 356 357 static void 358 getstr(int f, char *buf, int cnt, char *err) 359 { 360 char c; 361 do { 362 if (read(f, &c, 1) != 1 || (--cnt < 0)) { 363 syslog(LOG_ERR, "Error reading \'%s\' field", err); 364 exit(EXIT_FAILURE); 365 } 366 *buf++ = c; 367 } while (c != '\0'); 368 } 369 370 static krb5_error_code 371 recvauth(int f, 372 krb5_context krb_context, 373 unsigned int *valid_checksum, 374 krb5_ticket **ticket, 375 int *auth_type, 376 krb5_principal *client, 377 int encr_flag, 378 krb5_keytab keytab) 379 { 380 krb5_error_code status = 0; 381 krb5_auth_context auth_context = NULL; 382 krb5_rcache rcache; 383 krb5_authenticator *authenticator; 384 krb5_data inbuf; 385 krb5_data auth_version; 386 387 *valid_checksum = 0; 388 389 if ((status = krb5_auth_con_init(krb_context, &auth_context))) 390 return (status); 391 392 /* Only need remote address for rd_cred() to verify client */ 393 if ((status = krb5_auth_con_genaddrs(krb_context, auth_context, f, 394 KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR))) 395 return (status); 396 397 status = krb5_auth_con_getrcache(krb_context, auth_context, &rcache); 398 if (status) 399 return (status); 400 401 if (!rcache) { 402 krb5_principal server; 403 404 status = krb5_sname_to_principal(krb_context, 0, 0, 405 KRB5_NT_SRV_HST, &server); 406 if (status) 407 return (status); 408 409 status = krb5_get_server_rcache(krb_context, 410 krb5_princ_component(krb_context, server, 0), 411 &rcache); 412 krb5_free_principal(krb_context, server); 413 if (status) 414 return (status); 415 416 status = krb5_auth_con_setrcache(krb_context, auth_context, 417 rcache); 418 if (status) 419 return (status); 420 } 421 if ((status = krb5_compat_recvauth(krb_context, 422 &auth_context, 423 &f, 424 NULL, /* Specify daemon principal */ 425 0, /* no flags */ 426 keytab, /* NULL to use v5srvtab */ 427 ticket, /* return ticket */ 428 auth_type, /* authentication system */ 429 &auth_version))) { 430 if (*auth_type == KRB5_RECVAUTH_V5) { 431 /* 432 * clean up before exiting 433 */ 434 getstr(f, rusername, sizeof (rusername), "remuser"); 435 getstr(f, lusername, sizeof (lusername), "locuser"); 436 getstr(f, term, sizeof (term), "Terminal type"); 437 } 438 return (status); 439 } 440 441 getstr(f, lusername, sizeof (lusername), "locuser"); 442 getstr(f, term, sizeof (term), "Terminal type"); 443 444 kcmd_protocol = KCMD_UNKNOWN_PROTOCOL; 445 if (auth_version.length != 9 || auth_version.data == NULL) { 446 syslog(LOG_ERR, "Bad application protocol version length in " 447 "KRB5 exchange, exiting"); 448 fatal(f, "Bad application version length, exiting."); 449 } 450 /* 451 * Determine which Kerberos CMD protocol was used. 452 */ 453 if (strncmp(auth_version.data, "KCMDV0.1", 9) == 0) { 454 kcmd_protocol = KCMD_OLD_PROTOCOL; 455 } else if (strncmp(auth_version.data, "KCMDV0.2", 9) == 0) { 456 kcmd_protocol = KCMD_NEW_PROTOCOL; 457 } else { 458 syslog(LOG_ERR, "Unrecognized KCMD protocol (%s), exiting", 459 (char *)auth_version.data); 460 fatal(f, "Unrecognized KCMD protocol, exiting"); 461 } 462 463 if ((*auth_type == KRB5_RECVAUTH_V5) && chksum_flag && 464 kcmd_protocol == KCMD_OLD_PROTOCOL) { 465 if ((status = krb5_auth_con_getauthenticator(krb_context, 466 auth_context, 467 &authenticator))) 468 return (status); 469 if (authenticator->checksum) { 470 struct sockaddr_storage adr; 471 int adr_length = sizeof (adr); 472 int buflen; 473 krb5_data input; 474 krb5_keyblock key; 475 char *chksumbuf; 476 477 /* 478 * Define the lenght of the chksum buffer. 479 * chksum string = "[portnum]:termstr:username" 480 * The extra 32 is to hold a integer string for 481 * the portnumber. 482 */ 483 buflen = strlen(term) + strlen(lusername) + 32; 484 chksumbuf = (char *)malloc(buflen); 485 if (chksumbuf == 0) { 486 krb5_free_authenticator(krb_context, 487 authenticator); 488 fatal(f, "Out of memory error"); 489 } 490 491 if (getsockname(f, (struct sockaddr *)&adr, 492 &adr_length) != 0) { 493 krb5_free_authenticator(krb_context, 494 authenticator); 495 fatal(f, "getsockname error"); 496 } 497 498 (void) snprintf(chksumbuf, buflen, 499 "%u:%s%s", 500 ntohs(SOCK_PORT(adr)), 501 term, lusername); 502 503 input.data = chksumbuf; 504 input.length = strlen(chksumbuf); 505 key.contents = (*ticket)->enc_part2->session->contents; 506 key.length = (*ticket)->enc_part2->session->length; 507 status = krb5_c_verify_checksum(krb_context, 508 &key, 0, 509 &input, 510 authenticator->checksum, 511 valid_checksum); 512 513 if (status == 0 && *valid_checksum == 0) 514 status = KRB5KRB_AP_ERR_BAD_INTEGRITY; 515 516 if (chksumbuf) 517 krb5_xfree(chksumbuf); 518 if (status) { 519 krb5_free_authenticator(krb_context, 520 authenticator); 521 return (status); 522 } 523 } 524 krb5_free_authenticator(krb_context, authenticator); 525 } 526 527 if ((status = krb5_copy_principal(krb_context, 528 (*ticket)->enc_part2->client, 529 client))) 530 return (status); 531 532 /* Get the Unix username of the remote user */ 533 getstr(f, rusername, sizeof (rusername), "remuser"); 534 535 /* Get the Kerberos principal name string of the remote user */ 536 if ((status = krb5_unparse_name(krb_context, *client, &krusername))) 537 return (status); 538 539 #ifdef DEBUG 540 syslog(LOG_DEBUG | LOG_AUTH, "rlogind: got krb5 credentials for %s", 541 (krusername != NULL ? krusername : "<unknown>")); 542 #endif 543 544 if (encr_flag) { 545 status = krb5_auth_con_getremotesubkey(krb_context, 546 auth_context, 547 &session_key); 548 if (status) { 549 syslog(LOG_ERR, "Error getting KRB5 session " 550 "subkey, exiting"); 551 fatal(f, "Error getting KRB5 session subkey, exiting"); 552 } 553 /* 554 * The "new" protocol requires that a subkey be sent. 555 */ 556 if (session_key == NULL && 557 kcmd_protocol == KCMD_NEW_PROTOCOL) { 558 syslog(LOG_ERR, "No KRB5 session subkey sent, exiting"); 559 fatal(f, "No KRB5 session subkey sent, exiting"); 560 } 561 /* 562 * The "old" protocol does not permit an authenticator subkey. 563 * The key is taken from the ticket instead (see below). 564 */ 565 if (session_key != NULL && 566 kcmd_protocol == KCMD_OLD_PROTOCOL) { 567 syslog(LOG_ERR, "KRB5 session subkey not permitted " 568 "with old KCMD protocol, exiting"); 569 570 fatal(f, "KRB5 session subkey not permitted " 571 "with old KCMD protocol, exiting"); 572 } 573 /* 574 * If no key at this point, use the session key from 575 * the ticket. 576 */ 577 if (session_key == NULL) { 578 /* 579 * Save the session key so we can configure the crypto 580 * module later. 581 */ 582 status = krb5_copy_keyblock(krb_context, 583 (*ticket)->enc_part2->session, 584 &session_key); 585 if (status) { 586 syslog(LOG_ERR, "krb5_copy_keyblock failed"); 587 fatal(f, "krb5_copy_keyblock failed"); 588 } 589 } 590 /* 591 * If session key still cannot be found, we must 592 * exit because encryption is required here 593 * when encr_flag (-x) is set. 594 */ 595 if (session_key == NULL) { 596 syslog(LOG_ERR, "Could not find an encryption key," 597 "exiting"); 598 fatal(f, "Encryption required but key not found, " 599 "exiting"); 600 } 601 } 602 /* 603 * Use krb5_read_message to read the principal stuff. 604 */ 605 if ((status = krb5_read_message(krb_context, (krb5_pointer)&f, 606 &inbuf))) 607 fatal(f, "Error reading krb5 message"); 608 609 if (inbuf.length) { /* Forwarding being done, read creds */ 610 krb5_creds **creds = NULL; 611 612 if (status = krb5_rd_cred(krb_context, auth_context, &inbuf, 613 &creds, NULL)) { 614 if (rcache) 615 (void) krb5_rc_close(krb_context, rcache); 616 krb5_free_creds(krb_context, *creds); 617 fatal(f, "Can't get forwarded credentials"); 618 } 619 620 /* Store the forwarded creds in the ccache */ 621 if (status = store_forw_creds(krb_context, 622 creds, *ticket, lusername, 623 &ccache)) { 624 if (rcache) 625 (void) krb5_rc_close(krb_context, rcache); 626 krb5_free_creds(krb_context, *creds); 627 fatal(f, "Can't store forwarded credentials"); 628 } 629 krb5_free_creds(krb_context, *creds); 630 } 631 632 if (rcache) 633 (void) krb5_rc_close(krb_context, rcache); 634 635 return (status); 636 } 637 638 static void 639 do_krb_login(int f, char *host_addr, char *hostname, 640 krb5_context krb_context, int encr_flag, 641 krb5_keytab keytab) 642 { 643 krb5_error_code status; 644 uint_t valid_checksum; 645 krb5_ticket *ticket = NULL; 646 int auth_sys = 0; 647 int auth_sent = 0; 648 krb5_principal client = NULL; 649 650 if (getuid()) 651 fatal(f, "Error authorizing KRB5 connection, " 652 "server lacks privilege"); 653 654 status = recvauth(f, krb_context, &valid_checksum, &ticket, 655 &auth_sys, &client, encr_flag, keytab); 656 if (status) { 657 if (ticket) 658 krb5_free_ticket(krb_context, ticket); 659 if (status != 255) 660 syslog(LOG_ERR, 661 "Authentication failed from %s(%s): %s\n", 662 host_addr, hostname, error_message(status)); 663 fatal(f, "Kerberos authentication failed, exiting"); 664 } 665 666 if (auth_sys != KRB5_RECVAUTH_V5) { 667 fatal(f, "This server only supports Kerberos V5"); 668 } else { 669 /* 670 * Authenticated OK, now check authorization. 671 */ 672 if (client && krb5_kuserok(krb_context, client, lusername)) 673 auth_sent = KRB5_RECVAUTH_V5; 674 } 675 676 if (auth_sent == KRB5_RECVAUTH_V5 && 677 kcmd_protocol == KCMD_OLD_PROTOCOL && 678 chksum_flag == CHKSUM_REQUIRED && !valid_checksum) { 679 syslog(LOG_ERR, "Client did not supply required checksum, " 680 "connection rejected."); 681 fatal(f, "Client did not supply required checksum, " 682 "connection rejected."); 683 } 684 685 if (auth_sys != auth_sent) { 686 char *msg_fail = NULL; 687 int msgsize = 0; 688 689 if (ticket) 690 krb5_free_ticket(krb_context, ticket); 691 692 if (krusername != NULL) { 693 /* 694 * msgsize must be enough to hold 695 * krusername, lusername and a brief 696 * message describing the failure. 697 */ 698 msgsize = strlen(krusername) + 699 strlen(lusername) + 80; 700 msg_fail = (char *)malloc(msgsize); 701 } 702 if (msg_fail == NULL) { 703 syslog(LOG_ERR, "User is not authorized to login to " 704 "specified account"); 705 706 fatal(f, "User is not authorized to login to " 707 "specified account"); 708 } 709 if (auth_sent != 0) 710 (void) snprintf(msg_fail, msgsize, 711 "Access denied because of improper " 712 "KRB5 credentials"); 713 else 714 (void) snprintf(msg_fail, msgsize, 715 "User %s is not authorized to login " 716 "to account %s", 717 krusername, lusername); 718 syslog(LOG_ERR, "%s", msg_fail); 719 fatal(f, msg_fail); 720 } 721 } 722 723 /* 724 * stop_stream 725 * 726 * Utility routine to send a CRYPTIOCSTOP ioctl to the 727 * crypto module(cryptmod). 728 */ 729 static void 730 stop_stream(int fd, int dir) 731 { 732 struct strioctl crioc; 733 uint32_t stopdir = dir; 734 735 crioc.ic_cmd = CRYPTIOCSTOP; 736 crioc.ic_timout = -1; 737 crioc.ic_len = sizeof (stopdir); 738 crioc.ic_dp = (char *)&stopdir; 739 740 if (ioctl(fd, I_STR, &crioc)) 741 syslog(LOG_ERR, "Error sending CRYPTIOCSTOP ioctl: %m"); 742 } 743 744 /* 745 * start_stream 746 * 747 * Utility routine to send a CRYPTIOCSTART ioctl to the 748 * crypto module(cryptmod). This routine may contain optional 749 * payload data that the cryptmod will interpret as bytes that 750 * need to be decrypted and sent back up to the application 751 * via the data stream. 752 */ 753 static void 754 start_stream(int fd, int dir) 755 { 756 struct strioctl crioc; 757 uint32_t iocval; 758 size_t datalen = 0; 759 char *data = NULL; 760 761 if (dir == CRYPT_DECRYPT) { 762 iocval = CRYPTIOCSTARTDEC; 763 764 /* Look for data not yet processed */ 765 if (ioctl(fd, I_NREAD, &datalen) < 0) { 766 syslog(LOG_ERR, "I_NREAD returned error %m"); 767 datalen = 0; 768 } else { 769 if (datalen > 0) { 770 data = malloc(datalen); 771 if (data != NULL) { 772 int nbytes = read(fd, data, datalen); 773 datalen = nbytes; 774 } else { 775 syslog(LOG_ERR, 776 "malloc error (%d bytes)", 777 datalen); 778 datalen = 0; 779 } 780 } else { 781 datalen = 0; 782 } 783 } 784 } else { 785 iocval = CRYPTIOCSTARTENC; 786 } 787 788 crioc.ic_cmd = iocval; 789 crioc.ic_timout = -1; 790 crioc.ic_len = datalen; 791 crioc.ic_dp = data; 792 793 if (ioctl(fd, I_STR, &crioc)) 794 syslog(LOG_ERR, "Error sending CRYPTIOCSTART ioctl: %m"); 795 796 if (data != NULL) 797 free(data); 798 } 799 800 static int 801 configure_stream(int fd, krb5_keyblock *skey, int dir, krb5_data *ivec, 802 uint_t iv_usage) 803 { 804 struct cr_info_t setup_info; 805 struct strioctl crioc; 806 int retval = 0; 807 808 switch (skey->enctype) { 809 case ENCTYPE_DES_CBC_CRC: 810 setup_info.crypto_method = CRYPT_METHOD_DES_CBC_CRC; 811 break; 812 case ENCTYPE_DES_CBC_MD5: 813 setup_info.crypto_method = CRYPT_METHOD_DES_CBC_MD5; 814 break; 815 case ENCTYPE_DES_CBC_RAW: 816 setup_info.crypto_method = CRYPT_METHOD_DES_CBC_NULL; 817 break; 818 case ENCTYPE_DES3_CBC_SHA1: 819 setup_info.crypto_method = CRYPT_METHOD_DES3_CBC_SHA1; 820 break; 821 case ENCTYPE_ARCFOUR_HMAC: 822 setup_info.crypto_method = CRYPT_METHOD_ARCFOUR_HMAC_MD5; 823 break; 824 case ENCTYPE_ARCFOUR_HMAC_EXP: 825 setup_info.crypto_method = CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP; 826 break; 827 case ENCTYPE_AES128_CTS_HMAC_SHA1_96: 828 setup_info.crypto_method = CRYPT_METHOD_AES128; 829 break; 830 case ENCTYPE_AES256_CTS_HMAC_SHA1_96: 831 setup_info.crypto_method = CRYPT_METHOD_AES256; 832 break; 833 default: 834 syslog(LOG_ERR, "Enctype in kerberos session key " 835 "is not supported by crypto module(%d)", 836 skey->enctype); 837 return (-1); 838 } 839 if (ivec == NULL || ivec->length == 0) { 840 (void) memset(&setup_info.ivec, 0, sizeof (setup_info.ivec)); 841 842 if (skey->enctype != ENCTYPE_ARCFOUR_HMAC && 843 skey->enctype != ENCTYPE_ARCFOUR_HMAC_EXP) 844 /* Kerberos IVs are 8 bytes long for DES keys */ 845 setup_info.iveclen = KRB5_MIT_DES_KEYSIZE; 846 else 847 setup_info.iveclen = 0; 848 } else { 849 (void) memcpy(&setup_info.ivec, ivec->data, ivec->length); 850 setup_info.iveclen = ivec->length; 851 } 852 853 setup_info.ivec_usage = iv_usage; 854 (void) memcpy(&setup_info.key, skey->contents, skey->length); 855 856 setup_info.keylen = skey->length; 857 setup_info.direction_mask = dir; 858 /* 859 * R* commands get special handling by crypto module - 860 * 4 byte length field is used before each encrypted block 861 * of data. 862 */ 863 setup_info.option_mask = (kcmd_protocol == KCMD_OLD_PROTOCOL ? 864 CRYPTOPT_RCMD_MODE_V1 : 865 CRYPTOPT_RCMD_MODE_V2); 866 867 crioc.ic_cmd = CRYPTIOCSETUP; 868 crioc.ic_timout = -1; 869 crioc.ic_len = sizeof (setup_info); 870 crioc.ic_dp = (char *)&setup_info; 871 872 if (ioctl(fd, I_STR, &crioc)) { 873 syslog(LOG_ERR, "Error sending CRYPTIOCSETUP ioctl: %m"); 874 retval = -1; 875 } 876 return (retval); 877 } 878 879 static krb5_error_code 880 krb5_compat_recvauth(krb5_context context, 881 krb5_auth_context *auth_context, 882 krb5_pointer fdp, /* IN */ 883 krb5_principal server, /* IN */ 884 krb5_int32 flags, /* IN */ 885 krb5_keytab keytab, /* IN */ 886 krb5_ticket **ticket, /* OUT */ 887 krb5_int32 *auth_sys, /* OUT */ 888 krb5_data *version) /* OUT */ 889 { 890 krb5_int32 vlen; 891 char *buf; 892 int len, length; 893 krb5_int32 retval; 894 int fd = *((int *)fdp); 895 896 if ((retval = krb5_net_read(context, fd, (char *)&vlen, 4)) != 4) 897 return ((retval < 0) ? errno : ECONNABORTED); 898 899 /* 900 * Assume that we're talking to a V5 recvauth; read in the 901 * the version string, and make sure it matches. 902 */ 903 len = (int)ntohl(vlen); 904 905 if (len < 0 || len > 255) 906 return (KRB5_SENDAUTH_BADAUTHVERS); 907 908 buf = malloc(len); 909 if (buf == NULL) 910 return (ENOMEM); 911 912 length = krb5_net_read(context, fd, buf, len); 913 if (len != length) { 914 krb5_xfree(buf); 915 return ((len < 0) ? errno : ECONNABORTED); 916 } 917 918 if (strcmp(buf, KRB_V5_SENDAUTH_VERS) != 0) { 919 krb5_xfree(buf); 920 return (KRB5_SENDAUTH_BADAUTHVERS); 921 } 922 krb5_xfree(buf); 923 924 *auth_sys = KRB5_RECVAUTH_V5; 925 926 retval = krb5_recvauth_version(context, auth_context, fdp, 927 server, flags | KRB5_RECVAUTH_SKIP_VERSION, 928 keytab, ticket, version); 929 930 return (retval); 931 } 932 933 934 static void 935 doit(int f, 936 struct sockaddr_storage *fromp, 937 krb5_context krb_context, 938 int encr_flag, 939 krb5_keytab keytab) 940 { 941 int p, t, on = 1; 942 char c; 943 char abuf[INET6_ADDRSTRLEN]; 944 struct sockaddr_in *sin; 945 struct sockaddr_in6 *sin6; 946 int fromplen; 947 in_port_t port; 948 struct termios tp; 949 boolean_t bad_port; 950 boolean_t no_name; 951 char rhost_addra[INET6_ADDRSTRLEN]; 952 953 if (!(rlbuf = malloc(BUFSIZ))) { 954 syslog(LOG_ERR, "rlbuf malloc failed\n"); 955 exit(EXIT_FAILURE); 956 } 957 (void) alarm(60); 958 if (read(f, &c, 1) != 1 || c != 0) { 959 syslog(LOG_ERR, "failed to receive protocol zero byte\n"); 960 exit(EXIT_FAILURE); 961 } 962 (void) alarm(0); 963 if (fromp->ss_family == AF_INET) { 964 sin = (struct sockaddr_in *)fromp; 965 port = sin->sin_port = ntohs((ushort_t)sin->sin_port); 966 fromplen = sizeof (struct sockaddr_in); 967 968 if (!inet_ntop(AF_INET, &sin->sin_addr, 969 rhost_addra, sizeof (rhost_addra))) 970 goto badconversion; 971 } else if (fromp->ss_family == AF_INET6) { 972 sin6 = (struct sockaddr_in6 *)fromp; 973 port = sin6->sin6_port = ntohs((ushort_t)sin6->sin6_port); 974 fromplen = sizeof (struct sockaddr_in6); 975 976 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 977 struct in_addr ipv4_addr; 978 979 IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, 980 &ipv4_addr); 981 if (!inet_ntop(AF_INET, &ipv4_addr, rhost_addra, 982 sizeof (rhost_addra))) 983 goto badconversion; 984 } else { 985 if (!inet_ntop(AF_INET6, &sin6->sin6_addr, 986 rhost_addra, sizeof (rhost_addra))) 987 goto badconversion; 988 } 989 } else { 990 syslog(LOG_ERR, "unknown address family %d\n", 991 fromp->ss_family); 992 fatal(f, "Permission denied"); 993 } 994 995 /* 996 * Allow connections only from the "ephemeral" reserved 997 * ports(ports 512 - 1023) by checking the remote port 998 * because other utilities(e.g. in.ftpd) can be used to 999 * allow a unprivileged user to originate a connection 1000 * from a privileged port and provide untrustworthy 1001 * authentication. 1002 */ 1003 bad_port = (use_auth != KRB5_RECVAUTH_V5 && 1004 (port >= (in_port_t)IPPORT_RESERVED) || 1005 (port < (in_port_t)(IPPORT_RESERVED/2))); 1006 no_name = getnameinfo((const struct sockaddr *) fromp, 1007 fromplen, hostname, sizeof (hostname), 1008 NULL, 0, 0) != 0; 1009 1010 if (no_name || bad_port) { 1011 (void) strlcpy(abuf, rhost_addra, sizeof (abuf)); 1012 /* If no host name, use IP address for name later on. */ 1013 if (no_name) 1014 (void) strlcpy(hostname, abuf, sizeof (hostname)); 1015 } 1016 1017 if (!no_name) { 1018 /* 1019 * Even if getnameinfo() succeeded, we still have to check 1020 * for spoofing. 1021 */ 1022 check_address("rlogind", fromp, sin, sin6, rhost_addra, 1023 hostname, sizeof (hostname)); 1024 } 1025 1026 if (bad_port) { 1027 if (no_name) 1028 syslog(LOG_NOTICE, 1029 "connection from %s - bad port\n", 1030 abuf); 1031 else 1032 syslog(LOG_NOTICE, 1033 "connection from %s(%s) - bad port\n", 1034 hostname, abuf); 1035 fatal(f, "Permission denied"); 1036 } 1037 1038 if (use_auth == KRB5_RECVAUTH_V5) { 1039 do_krb_login(f, rhost_addra, hostname, 1040 krb_context, encr_flag, keytab); 1041 if (krusername != NULL && strlen(krusername)) { 1042 /* 1043 * Kerberos Authentication succeeded, 1044 * so set the proper program name to use 1045 * with pam (important during 'cleanup' 1046 * routine later). 1047 */ 1048 pam_prog_name = KRB5_PROG_NAME; 1049 } 1050 } 1051 1052 if (write(f, "", 1) != 1) { 1053 syslog(LOG_NOTICE, 1054 "send of the zero byte(to %s) failed:" 1055 " cannot start data transfer mode\n", 1056 (no_name ? abuf : hostname)); 1057 exit(EXIT_FAILURE); 1058 } 1059 if ((p = open("/dev/ptmx", O_RDWR)) == -1) 1060 fatalperror(f, "cannot open /dev/ptmx"); 1061 if (grantpt(p) == -1) 1062 fatal(f, "could not grant slave pty"); 1063 if (unlockpt(p) == -1) 1064 fatal(f, "could not unlock slave pty"); 1065 if ((line = ptsname(p)) == NULL) 1066 fatal(f, "could not enable slave pty"); 1067 if ((t = open(line, O_RDWR)) == -1) 1068 fatal(f, "could not open slave pty"); 1069 if (ioctl(t, I_PUSH, "ptem") == -1) 1070 fatalperror(f, "ioctl I_PUSH ptem"); 1071 if (ioctl(t, I_PUSH, "ldterm") == -1) 1072 fatalperror(f, "ioctl I_PUSH ldterm"); 1073 if (ioctl(t, I_PUSH, "ttcompat") == -1) 1074 fatalperror(f, "ioctl I_PUSH ttcompat"); 1075 /* 1076 * POP the sockmod and push the rlmod module. 1077 * 1078 * Note that sockmod has to be removed since readstream assumes 1079 * a "raw" TPI endpoint(e.g. it uses getmsg). 1080 */ 1081 if (removemod(f, "sockmod") < 0) 1082 fatalperror(f, "couldn't remove sockmod"); 1083 1084 if (encr_flag) { 1085 if (ioctl(f, I_PUSH, "cryptmod") < 0) 1086 fatalperror(f, "ioctl I_PUSH rlmod"); 1087 1088 } 1089 1090 if (ioctl(f, I_PUSH, "rlmod") < 0) 1091 fatalperror(f, "ioctl I_PUSH rlmod"); 1092 1093 if (encr_flag) { 1094 /* 1095 * Make sure rlmod will pass unrecognized IOCTLs to cryptmod 1096 */ 1097 uchar_t passthru = 1; 1098 struct strioctl rlmodctl; 1099 1100 rlmodctl.ic_cmd = CRYPTPASSTHRU; 1101 rlmodctl.ic_timout = -1; 1102 rlmodctl.ic_len = sizeof (uchar_t); 1103 rlmodctl.ic_dp = (char *)&passthru; 1104 1105 if (ioctl(f, I_STR, &rlmodctl) < 0) 1106 fatal(f, "ioctl CRYPTPASSTHRU failed\n"); 1107 } 1108 1109 /* 1110 * readstream will do a getmsg till it receives 1111 * M_PROTO type T_DATA_REQ from rloginmodopen() 1112 * indicating all data on the stream prior to pushing rlmod has 1113 * been drained at the stream head. 1114 */ 1115 if ((nsize = readstream(f, rlbuf, BUFSIZ)) < 0) 1116 fatalperror(f, "readstream failed"); 1117 /* 1118 * Make sure the pty doesn't modify the strings passed 1119 * to login as part of the "rlogin protocol." The login 1120 * program should set these flags to apropriate values 1121 * after it has read the strings. 1122 */ 1123 if (ioctl(t, TCGETS, &tp) == -1) 1124 fatalperror(f, "ioctl TCGETS"); 1125 tp.c_lflag &= ~(ECHO|ICANON); 1126 tp.c_oflag &= ~(XTABS|OCRNL); 1127 tp.c_iflag &= ~(IGNPAR|ICRNL); 1128 if (ioctl(t, TCSETS, &tp) == -1) 1129 fatalperror(f, "ioctl TCSETS"); 1130 1131 /* 1132 * System V ptys allow the TIOC{SG}WINSZ ioctl to be 1133 * issued on the master side of the pty. Luckily, that's 1134 * the only tty ioctl we need to do do, so we can close the 1135 * slave side in the parent process after the fork. 1136 */ 1137 (void) ioctl(p, TIOCSWINSZ, &win); 1138 1139 pid = fork(); 1140 if (pid < 0) 1141 fatalperror(f, "fork"); 1142 if (pid == 0) { 1143 int tt; 1144 struct utmpx ut; 1145 1146 /* System V login expects a utmp entry to already be there */ 1147 (void) memset(&ut, 0, sizeof (ut)); 1148 (void) strncpy(ut.ut_user, ".rlogin", sizeof (ut.ut_user)); 1149 (void) strncpy(ut.ut_line, line, sizeof (ut.ut_line)); 1150 ut.ut_pid = getpid(); 1151 ut.ut_id[0] = 'r'; 1152 ut.ut_id[1] = (char)SC_WILDC; 1153 ut.ut_id[2] = (char)SC_WILDC; 1154 ut.ut_id[3] = (char)SC_WILDC; 1155 ut.ut_type = LOGIN_PROCESS; 1156 ut.ut_exit.e_termination = 0; 1157 ut.ut_exit.e_exit = 0; 1158 (void) time(&ut.ut_tv.tv_sec); 1159 if (makeutx(&ut) == NULL) 1160 syslog(LOG_INFO, "in.rlogind:\tmakeutx failed"); 1161 1162 /* controlling tty */ 1163 if (setsid() == -1) 1164 fatalperror(f, "setsid"); 1165 if ((tt = open(line, O_RDWR)) == -1) 1166 fatalperror(f, "could not re-open slave pty"); 1167 1168 if (close(p) == -1) 1169 fatalperror(f, "error closing pty master"); 1170 if (close(t) == -1) 1171 fatalperror(f, "error closing pty slave" 1172 " opened before session established"); 1173 /* 1174 * If this fails we may or may not be able to output an 1175 * error message. 1176 */ 1177 if (close(f) == -1) 1178 fatalperror(f, "error closing deamon stdout"); 1179 if (dup2(tt, STDIN_FILENO) == -1 || 1180 dup2(tt, STDOUT_FILENO) == -1 || 1181 dup2(tt, STDERR_FILENO) == -1) 1182 exit(EXIT_FAILURE); /* Disaster! No stderr! */ 1183 1184 (void) close(tt); 1185 1186 if (use_auth == KRB5_RECVAUTH_V5 && 1187 krusername != NULL && strlen(krusername)) { 1188 (void) execl(LOGIN_PROGRAM, "login", 1189 "-d", line, 1190 "-r", hostname, 1191 "-u", krusername, /* KRB5 principal name */ 1192 "-s", pam_prog_name, 1193 "-t", term, /* Remote Terminal */ 1194 "-U", rusername, /* Remote User */ 1195 "-R", KRB5_REPOSITORY_NAME, 1196 lusername, /* local user */ 1197 NULL); 1198 } else { 1199 (void) execl(LOGIN_PROGRAM, "login", 1200 "-d", line, 1201 "-r", hostname, 1202 NULL); 1203 } 1204 1205 fatalperror(STDERR_FILENO, "/bin/login"); 1206 /*NOTREACHED*/ 1207 } 1208 (void) close(t); 1209 (void) ioctl(f, FIONBIO, &on); 1210 (void) ioctl(p, FIONBIO, &on); 1211 1212 /* 1213 * Must ignore SIGTTOU, otherwise we'll stop 1214 * when we try and set slave pty's window shape 1215 * (our controlling tty is the master pty). 1216 * Likewise, we don't want any of the tty-generated 1217 * signals from chars passing through. 1218 */ 1219 (void) sigset(SIGTSTP, SIG_IGN); 1220 (void) sigset(SIGINT, SIG_IGN); 1221 (void) sigset(SIGQUIT, SIG_IGN); 1222 (void) sigset(SIGTTOU, SIG_IGN); 1223 (void) sigset(SIGTTIN, SIG_IGN); 1224 (void) sigset(SIGCHLD, cleanup); 1225 (void) setpgrp(); 1226 1227 if (encr_flag) { 1228 krb5_data ivec, *ivptr; 1229 uint_t ivec_usage; 1230 stop_stream(f, CRYPT_ENCRYPT|CRYPT_DECRYPT); 1231 1232 /* 1233 * Configure the STREAMS crypto module. For now, 1234 * don't use any IV parameter. KCMDV0.2 support 1235 * will require the use of Initialization Vectors 1236 * for both encrypt and decrypt modes. 1237 */ 1238 if (kcmd_protocol == KCMD_OLD_PROTOCOL) { 1239 if (session_key->enctype == ENCTYPE_DES_CBC_CRC) { 1240 /* 1241 * This is gross but necessary for MIT compat. 1242 */ 1243 ivec.length = session_key->length; 1244 ivec.data = (char *)session_key->contents; 1245 ivec_usage = IVEC_REUSE; 1246 ivptr = &ivec; 1247 } else { 1248 ivptr = NULL; /* defaults to all 0's */ 1249 ivec_usage = IVEC_NEVER; 1250 } 1251 /* 1252 * configure both sides of stream together 1253 * since they share the same IV. 1254 * This is what makes the OLD KCMD protocol 1255 * less secure than the newer one - Bad ivecs. 1256 */ 1257 if (configure_stream(f, session_key, 1258 CRYPT_ENCRYPT|CRYPT_DECRYPT, 1259 ivptr, ivec_usage) != 0) 1260 fatal(f, "Cannot initialize encryption -" 1261 " exiting.\n"); 1262 } else { 1263 size_t blocksize; 1264 if (session_key->enctype == ENCTYPE_ARCFOUR_HMAC || 1265 session_key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { 1266 if (configure_stream(f, session_key, 1267 CRYPT_ENCRYPT|CRYPT_DECRYPT, 1268 NULL, IVEC_NEVER) != 0) 1269 fatal(f, 1270 "Cannot initialize encryption -" 1271 " exiting.\n"); 1272 goto startcrypto; 1273 } 1274 if (krb5_c_block_size(krb_context, 1275 session_key->enctype, 1276 &blocksize)) { 1277 syslog(LOG_ERR, "Cannot determine blocksize " 1278 "for encryption type %d", 1279 session_key->enctype); 1280 fatal(f, "Cannot determine blocksize " 1281 "for encryption - exiting.\n"); 1282 } 1283 ivec.data = (char *)malloc(blocksize); 1284 ivec.length = blocksize; 1285 if (ivec.data == NULL) 1286 fatal(f, "memory error - exiting\n"); 1287 /* 1288 * Following MIT convention - 1289 * encrypt IV = 0x01 x blocksize 1290 * decrypt IV = 0x00 x blocksize 1291 * ivec_usage = IVEC_ONETIME 1292 * 1293 * configure_stream separately for encrypt and 1294 * decrypt because there are 2 different IVs. 1295 * 1296 * AES uses 0's for IV. 1297 */ 1298 if (session_key->enctype == 1299 ENCTYPE_AES128_CTS_HMAC_SHA1_96 || 1300 session_key->enctype == 1301 ENCTYPE_AES256_CTS_HMAC_SHA1_96) 1302 (void) memset(ivec.data, 0x00, blocksize); 1303 else 1304 (void) memset(ivec.data, 0x01, blocksize); 1305 if (configure_stream(f, session_key, CRYPT_ENCRYPT, 1306 &ivec, IVEC_ONETIME) != 0) 1307 fatal(f, "Cannot initialize encryption -" 1308 " exiting.\n"); 1309 (void) memset(ivec.data, 0x00, blocksize); 1310 if (configure_stream(f, session_key, CRYPT_DECRYPT, 1311 &ivec, IVEC_ONETIME) != 0) 1312 fatal(f, "Cannot initialize encryption -" 1313 " exiting.\n"); 1314 1315 (void) free(ivec.data); 1316 } 1317 startcrypto: 1318 start_stream(f, CRYPT_ENCRYPT); 1319 start_stream(f, CRYPT_DECRYPT); 1320 } 1321 protocol(f, p, encr_flag); 1322 cleanup(0); 1323 /*NOTREACHED*/ 1324 1325 badconversion: 1326 fatalperror(f, "address conversion"); 1327 /*NOTREACHED*/ 1328 } 1329 1330 /* 1331 * rlogin "protocol" machine. 1332 */ 1333 static void 1334 protocol(int f, int p, int encr_flag) 1335 { 1336 struct stat buf; 1337 struct protocol_arg rloginp; 1338 struct strioctl rloginmod; 1339 int ptmfd; /* fd of logindmux coneected to ptmx */ 1340 int netfd; /* fd of logindmux connected to netf */ 1341 static uchar_t oobdata[] = {TIOCPKT_WINDOW}; 1342 1343 /* indicate new rlogin */ 1344 if (send_oob(f, oobdata, 1) < 0) 1345 fatalperror(f, "send_oob"); 1346 /* 1347 * We cannot send the SECURE_MSG until after the 1348 * client has been signaled with the oobdata (above). 1349 */ 1350 if (encr_flag) { 1351 if (write(f, SECURE_MSG, strlen(SECURE_MSG)) < 0) 1352 fatalperror(f, "Error writing SECURE message"); 1353 } 1354 1355 /* 1356 * Open logindmux driver and link netf and ptmx 1357 * underneath logindmux. 1358 */ 1359 if ((ptmfd = open("/dev/logindmux", O_RDWR)) == -1) 1360 fatalperror(f, "open /dev/logindmux"); 1361 1362 if ((netfd = open("/dev/logindmux", O_RDWR)) == -1) 1363 fatalperror(f, "open /dev/logindmux"); 1364 1365 if (ioctl(ptmfd, I_LINK, p) < 0) 1366 fatal(f, "ioctl I_LINK of /dev/ptmx failed\n"); 1367 1368 if (ioctl(netfd, I_LINK, f) < 0) 1369 fatal(f, "ioctl I_LINK of tcp connection failed\n"); 1370 1371 /* 1372 * Figure out the device number of the ptm's mux fd, and pass that 1373 * to the net's mux. 1374 */ 1375 if (fstat(ptmfd, &buf) < 0) 1376 fatalperror(f, "cannot determine device number" 1377 " of pty side of /dev/logindmux"); 1378 rloginp.dev = buf.st_rdev; 1379 rloginp.flag = 0; 1380 1381 rloginmod.ic_cmd = LOGDMX_IOC_QEXCHANGE; 1382 rloginmod.ic_timout = -1; 1383 rloginmod.ic_len = sizeof (struct protocol_arg); 1384 rloginmod.ic_dp = (char *)&rloginp; 1385 1386 if (ioctl(netfd, I_STR, &rloginmod) < 0) 1387 fatal(netfd, "ioctl LOGDMX_IOC_QEXCHANGE of netfd failed\n"); 1388 1389 /* 1390 * Figure out the device number of the net's mux fd, and pass that 1391 * to the ptm's mux. 1392 */ 1393 if (fstat(netfd, &buf)) 1394 fatalperror(f, "cannot determine device number" 1395 " of network side of /dev/logindmux"); 1396 rloginp.dev = buf.st_rdev; 1397 rloginp.flag = 1; 1398 1399 rloginmod.ic_cmd = LOGDMX_IOC_QEXCHANGE; 1400 rloginmod.ic_timout = -1; 1401 rloginmod.ic_len = sizeof (struct protocol_arg); 1402 rloginmod.ic_dp = (char *)&rloginp; 1403 1404 if (ioctl(ptmfd, I_STR, &rloginmod) < 0) 1405 fatal(netfd, "ioctl LOGDMXZ_IOC_QEXCHANGE of ptmfd failed\n"); 1406 /* 1407 * Send an ioctl type RL_IOC_ENABLE to reenable the 1408 * message queue and reinsert the data read from streamhead 1409 * at the time of pushing rloginmod module. 1410 * We need to send this ioctl even if no data was read earlier 1411 * since we need to reenable the message queue of rloginmod module. 1412 */ 1413 rloginmod.ic_cmd = RL_IOC_ENABLE; 1414 rloginmod.ic_timout = -1; 1415 if (nsize) { 1416 rloginmod.ic_len = nsize; 1417 rloginmod.ic_dp = rlbuf; 1418 } else { 1419 rloginmod.ic_len = 0; 1420 rloginmod.ic_dp = NULL; 1421 } 1422 1423 if (ioctl(netfd, I_STR, &rloginmod) < 0) 1424 fatal(netfd, "ioctl RL_IOC_ENABLE of netfd failed\n"); 1425 1426 /* 1427 * User level daemon now pauses till the shell exits. 1428 */ 1429 (void) pause(); 1430 } 1431 1432 /* This is a signal handler, hence the dummy argument */ 1433 /*ARGSUSED*/ 1434 static void 1435 cleanup(int dummy) 1436 { 1437 rmut(); 1438 exit(EXIT_FAILURE); 1439 /*NOTREACHED*/ 1440 } 1441 1442 /* 1443 * TPI style replacement for socket send() primitive, so we don't require 1444 * sockmod to be on the stream. 1445 */ 1446 static int 1447 send_oob(int fd, void *ptr, size_t count) 1448 { 1449 struct T_exdata_req exd_req; 1450 struct strbuf hdr, dat; 1451 int ret; 1452 1453 exd_req.PRIM_type = T_EXDATA_REQ; 1454 exd_req.MORE_flag = 0; 1455 1456 hdr.buf = (char *)&exd_req; 1457 hdr.len = sizeof (exd_req); 1458 1459 dat.buf = ptr; 1460 dat.len = count; 1461 1462 ret = putmsg(fd, &hdr, &dat, 0); 1463 if (ret == 0) 1464 ret = count; 1465 return (ret); 1466 } 1467 1468 static void 1469 fatal(int fd, const char *msg) 1470 { 1471 char *bufp; 1472 size_t len = strlen(msg) + 16; /* enough for our wrapper */ 1473 1474 bufp = alloca(len); 1475 /* ASCII 001 is the error indicator */ 1476 len = snprintf(bufp, len, "\01rlogind: %s.\r\n", msg); 1477 (void) write(fd, bufp, len); 1478 exit(EXIT_FAILURE); 1479 /*NOTREACHED*/ 1480 } 1481 1482 /*PRINTFLIKE2*/ 1483 static void 1484 fatalperror(int fd, const char *msg) 1485 { 1486 char *bufp; 1487 const char *errstr; 1488 int save_errno = errno; 1489 size_t len = strlen(msg); 1490 1491 if ((errstr = strerror(save_errno))) { 1492 len += strlen(errstr) + 3; /* 3 for ": " and \0 below */ 1493 bufp = alloca(len); 1494 (void) snprintf(bufp, len, "%s: %s", msg, errstr); 1495 } else { 1496 const char fmt[] = "%s: Error %d"; 1497 1498 /* -4 for %s & %d. "*8/3" is bytes->decimal, pessimistically */ 1499 len += sizeof (fmt) -4 + (sizeof (save_errno) *8 /3); 1500 bufp = alloca(len); 1501 (void) snprintf(bufp, len, fmt, msg, save_errno); 1502 } 1503 fatal(fd, bufp); 1504 /*NOTREACHED*/ 1505 } 1506 1507 static void 1508 rmut(void) 1509 { 1510 pam_handle_t *pamh; 1511 struct utmpx *up; 1512 char user[sizeof (up->ut_user) + 1]; 1513 char ttyn[sizeof (up->ut_line) + 1]; 1514 char rhost[sizeof (up->ut_host) + 1]; 1515 1516 /* while cleaning up dont allow disruption */ 1517 (void) sigset(SIGCHLD, SIG_IGN); 1518 1519 setutxent(); 1520 while (up = getutxent()) { 1521 if (up->ut_pid == pid) { 1522 if (up->ut_type == DEAD_PROCESS) 1523 break; /* Cleaned up elsewhere. */ 1524 1525 /* 1526 * call pam_close_session if login changed 1527 * the utmpx user entry from type LOGIN_PROCESS 1528 * to type USER_PROCESS, which happens 1529 * after pam_open_session is called. 1530 */ 1531 if (up->ut_type == USER_PROCESS) { 1532 (void) strlcpy(user, up->ut_user, 1533 sizeof (user)); 1534 (void) strlcpy(ttyn, up->ut_line, 1535 sizeof (ttyn)); 1536 (void) strlcpy(rhost, up->ut_host, 1537 sizeof (rhost)); 1538 1539 /* 1540 * Use the same pam_prog_name that 1541 * 'login' used. 1542 */ 1543 if ((pam_start(pam_prog_name, user, NULL, 1544 &pamh)) 1545 == PAM_SUCCESS) { 1546 (void) pam_set_item(pamh, PAM_TTY, 1547 ttyn); 1548 (void) pam_set_item(pamh, PAM_RHOST, 1549 rhost); 1550 (void) pam_close_session(pamh, 0); 1551 (void) pam_end(pamh, PAM_SUCCESS); 1552 } 1553 } 1554 1555 up->ut_type = DEAD_PROCESS; 1556 up->ut_exit.e_termination = WTERMSIG(0); 1557 up->ut_exit.e_exit = WEXITSTATUS(0); 1558 (void) time(&up->ut_tv.tv_sec); 1559 1560 if (modutx(up) == NULL) { 1561 /* 1562 * Since modutx failed we'll 1563 * write out the new entry 1564 * ourselves. 1565 */ 1566 (void) pututxline(up); 1567 updwtmpx("wtmpx", up); 1568 } 1569 break; 1570 } 1571 } 1572 1573 endutxent(); 1574 1575 (void) sigset(SIGCHLD, cleanup); 1576 } 1577 1578 static int 1579 readstream(int fd, char *buf, int size) 1580 { 1581 struct strbuf ctlbuf, datbuf; 1582 union T_primitives tpi; 1583 int nbytes = 0; 1584 int ret = 0; 1585 int flags = 0; 1586 int bufsize = size; 1587 int nread; 1588 1589 (void) memset(&ctlbuf, 0, sizeof (ctlbuf)); 1590 (void) memset(&datbuf, 0, sizeof (datbuf)); 1591 1592 ctlbuf.buf = (char *)&tpi; 1593 ctlbuf.maxlen = sizeof (tpi); 1594 datbuf.buf = buf; 1595 datbuf.maxlen = size; 1596 1597 for (;;) { 1598 if (ioctl(fd, I_NREAD, &nread) < 0) { 1599 syslog(LOG_ERR, "I_NREAD returned error %m"); 1600 return (-1); 1601 } 1602 if (nread + nbytes > bufsize) { 1603 buf = (char *)realloc(buf, (unsigned)(bufsize + nread)); 1604 if (buf == NULL) { 1605 syslog(LOG_WARNING, 1606 "buffer allocation failed\n"); 1607 return (-1); 1608 } 1609 bufsize += nread; 1610 rlbuf = buf; 1611 datbuf.buf = buf + nbytes; 1612 } 1613 datbuf.maxlen = bufsize - nbytes; 1614 ret = getmsg(fd, &ctlbuf, &datbuf, &flags); 1615 if (ret < 0) { 1616 syslog(LOG_ERR, "getmsg failed error %m"); 1617 return (-1); 1618 } 1619 if ((ctlbuf.len == 0) && (datbuf.len == 0)) { 1620 /* 1621 * getmsg() returned no data - this indicates 1622 * that the connection is closing down. 1623 */ 1624 cleanup(0); 1625 } 1626 if (ctlbuf.len <= 0) { 1627 nbytes += datbuf.len; 1628 datbuf.buf += datbuf.len; 1629 continue; 1630 } 1631 if (tpi.type == T_DATA_REQ) { 1632 return (nbytes); 1633 } 1634 if ((tpi.type == T_ORDREL_IND) || (tpi.type == T_DISCON_IND)) 1635 cleanup(0); 1636 } 1637 } 1638 1639 /* 1640 * Verify that the named module is at the top of the stream 1641 * and then pop it off. 1642 */ 1643 static int 1644 removemod(int f, char *modname) 1645 { 1646 char topmodname[BUFSIZ]; 1647 1648 if (ioctl(f, I_LOOK, topmodname) < 0) 1649 return (-1); 1650 if (strcmp(modname, topmodname) != 0) { 1651 errno = ENXIO; 1652 return (-1); 1653 } 1654 if (ioctl(f, I_POP, 0) < 0) 1655 return (-1); 1656 return (0); 1657 } 1658