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