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