1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1983-1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Portions of this source code were derived from Berkeley 4.3 BSD 32 * under license from the Regents of the University of California. 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 #define _FILE_OFFSET_BITS 64 38 39 /* 40 * remote shell server: 41 * remuser\0 42 * locuser\0 43 * command\0 44 * data 45 */ 46 #include <sys/types.h> 47 #include <sys/ioctl.h> 48 #include <sys/telioctl.h> 49 #include <sys/param.h> 50 #include <sys/socket.h> 51 #include <sys/time.h> 52 #include <sys/stat.h> 53 #include <sys/file.h> 54 #include <sys/select.h> 55 56 #include <netinet/in.h> 57 58 #include <arpa/inet.h> 59 60 #include <unistd.h> 61 #include <string.h> 62 #include <stdio.h> 63 #include <stdarg.h> 64 #include <errno.h> 65 #include <pwd.h> 66 #include <grp.h> 67 #include <signal.h> 68 #include <netdb.h> 69 #include <syslog.h> 70 #include <fcntl.h> 71 #include <ctype.h> 72 #include <locale.h> 73 74 #include <sys/resource.h> 75 #include <sys/filio.h> 76 #include <shadow.h> 77 #include <stdlib.h> 78 79 #include <security/pam_appl.h> 80 81 #include <k5-int.h> 82 #include <krb5_repository.h> 83 #include <com_err.h> 84 #include <kcmd.h> 85 86 #include <addr_match.h> 87 #include <store_forw_creds.h> 88 89 #ifndef NCARGS 90 #define NCARGS 5120 91 #endif /* !NCARGS */ 92 93 static void error(char *, ...); 94 static void doit(int, struct sockaddr_storage *, char **); 95 static void getstr(int, char *, int, char *); 96 97 static int legalenvvar(char *); 98 static void add_to_envinit(char *); 99 static int locale_envmatch(char *, char *); 100 101 /* Function decls. for functions not in any header file. (Grrrr.) */ 102 extern int audit_rshd_setup(void); 103 extern int audit_rshd_success(char *, char *, char *, char *); 104 extern int audit_rshd_fail(char *, char *, char *, char *, char *); 105 extern int audit_settid(int); 106 107 static int do_encrypt = 0; 108 static pam_handle_t *pamh; 109 110 /* 111 * This is the shell/kshell daemon. The very basic protocol for checking 112 * authentication and authorization is: 113 * 1) Check authentication. 114 * 2) Check authorization via the access-control files: 115 * ~/.k5login (using krb5_kuserok) and/or 116 * Execute command if configured authoriztion checks pass, else deny 117 * permission. 118 * 119 * The configuration is done either by command-line arguments passed by inetd, 120 * or by the name of the daemon. If command-line arguments are present, they 121 * take priority. The options are: 122 * -k allow kerberos authentication (krb5 only; krb4 support is not provided) 123 * -5 same as `-k', mainly for compatability with MIT 124 * -e allow encrypted session 125 * -c demand authenticator checksum 126 * -i ignore authenticator checksum 127 * -U Refuse connections that cannot be mapped to a name via `gethostbyname' 128 * -s <tos> Set the IP TOS option 129 * -S <keytab> Set the keytab file to use 130 * -M <realm> Set the Kerberos realm to use 131 */ 132 133 #define ARGSTR "ek5ciUD:M:S:L:?:" 134 #define RSHD_BUFSIZ (50 * 1024) 135 136 static krb5_context bsd_context; 137 static krb5_keytab keytab = NULL; 138 static krb5_ccache ccache = NULL; 139 static krb5_keyblock *sessionkey = NULL; 140 141 static int require_encrypt = 0; 142 static int resolve_hostname = 0; 143 static int krb5auth_flag = 0; /* Flag set, when KERBEROS is enabled */ 144 static enum kcmd_proto kcmd_protocol; 145 146 #ifdef DEBUG 147 static int debug_port = 0; 148 #endif /* DEBUG */ 149 150 /* 151 * There are two authentication related masks: 152 * auth_ok and auth_sent. 153 * The auth_ok mask is the or'ing of authentication 154 * systems any one of which can be used. 155 * The auth_sent mask is the or'ing of one or more authentication/authorization 156 * systems that succeeded. If the and'ing 157 * of these two masks is true, then authorization is successful. 158 */ 159 160 #define AUTH_KRB5 (0x2) 161 static int auth_ok = 0; 162 static int auth_sent = 0; 163 static int checksum_required = 0; 164 static int checksum_ignored = 0; 165 166 /* 167 * Leave room for 4 environment variables to be passed. 168 * The "-L env_var" option has been added primarily to 169 * maintain compatability with MIT. 170 */ 171 #define MAXENV 4 172 static char *save_env[MAXENV]; 173 static int num_env = 0; 174 175 static void usage(void); 176 static krb5_error_code recvauth(int, int *); 177 178 /*ARGSUSED*/ 179 int 180 main(int argc, char **argv, char **renvp) 181 { 182 struct linger linger; 183 int on = 1, fromlen; 184 struct sockaddr_storage from; 185 int fd = 0; 186 187 extern int opterr, optind; 188 extern char *optarg; 189 int ch; 190 int tos = -1; 191 krb5_error_code status; 192 193 openlog("rsh", LOG_PID | LOG_ODELAY, LOG_DAEMON); 194 (void) audit_rshd_setup(); /* BSM */ 195 fromlen = sizeof (from); 196 197 (void) setlocale(LC_ALL, ""); 198 199 /* 200 * Analyze parameters. 201 */ 202 opterr = 0; 203 while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 204 switch (ch) { 205 case '5': 206 case 'k': 207 auth_ok |= AUTH_KRB5; 208 krb5auth_flag++; 209 break; 210 211 case 'c': 212 checksum_required = 1; 213 krb5auth_flag++; 214 break; 215 case 'i': 216 checksum_ignored = 1; 217 krb5auth_flag++; 218 break; 219 220 case 'e': 221 require_encrypt = 1; 222 krb5auth_flag++; 223 break; 224 #ifdef DEBUG 225 case 'D': 226 debug_port = atoi(optarg); 227 break; 228 #endif /* DEBUG */ 229 case 'U': 230 resolve_hostname = 1; 231 break; 232 233 case 'M': 234 krb5_set_default_realm(bsd_context, optarg); 235 krb5auth_flag++; 236 break; 237 238 case 'S': 239 if ((status = krb5_kt_resolve(bsd_context, optarg, 240 &keytab))) { 241 com_err("rsh", status, 242 gettext("while resolving " 243 "srvtab file %s"), optarg); 244 exit(2); 245 } 246 krb5auth_flag++; 247 break; 248 249 case 's': 250 if (optarg == NULL || ((tos = atoi(optarg)) < 0) || 251 (tos > 255)) { 252 syslog(LOG_ERR, "rshd: illegal tos value: " 253 "%s\n", optarg); 254 } 255 break; 256 257 case 'L': 258 if (num_env < MAXENV) { 259 save_env[num_env] = strdup(optarg); 260 if (!save_env[num_env++]) { 261 com_err("rsh", ENOMEM, 262 gettext("in saving env")); 263 exit(2); 264 } 265 } else { 266 (void) fprintf(stderr, gettext("rshd: Only %d" 267 " -L arguments allowed\n"), 268 MAXENV); 269 exit(2); 270 } 271 break; 272 273 case '?': 274 default: 275 usage(); 276 exit(1); 277 break; 278 } 279 280 if (optind == 0) { 281 usage(); 282 exit(1); 283 } 284 argc -= optind; 285 argv += optind; 286 287 if (krb5auth_flag > 0) { 288 status = krb5_init_context(&bsd_context); 289 if (status) { 290 syslog(LOG_ERR, "Error initializing krb5: %s", 291 error_message(status)); 292 exit(1); 293 } 294 } 295 296 if (!checksum_required && !checksum_ignored) 297 checksum_ignored = 1; 298 299 if (checksum_required && checksum_ignored) { 300 syslog(LOG_CRIT, gettext("Checksums are required and ignored." 301 "These options are mutually exclusive" 302 "--check the documentation.")); 303 error("Configuration error: mutually exclusive " 304 "options specified.\n"); 305 exit(1); 306 } 307 308 #ifdef DEBUG 309 if (debug_port) { 310 int s; 311 struct sockaddr_in sin; 312 313 if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) { 314 fprintf(stderr, gettext("Error in socket: %s\n"), 315 strerror(errno)); 316 exit(2); 317 } 318 (void) memset((char *)&sin, 0, sizeof (sin)); 319 sin.sin_family = AF_INET; 320 sin.sin_port = htons(debug_port); 321 sin.sin_addr.s_addr = INADDR_ANY; 322 323 (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 324 (char *)&on, sizeof (on)); 325 326 if ((bind(s, (struct sockaddr *)&sin, sizeof (sin))) < 0) { 327 (void) fprintf(stderr, gettext("Error in bind: %s\n"), 328 strerror(errno)); 329 exit(2); 330 } 331 if ((listen(s, 5)) < 0) { 332 (void) fprintf(stderr, gettext("Error in listen: %s\n"), 333 strerror(errno)); 334 exit(2); 335 } 336 if ((fd = accept(s, (struct sockaddr *)&from, 337 &fromlen)) < 0) { 338 (void) fprintf(stderr, gettext("Error in accept: %s\n"), 339 strerror(errno)); 340 exit(2); 341 } 342 (void) close(s); 343 } 344 else 345 #endif /* DEBUG */ 346 { 347 if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, 348 (socklen_t *)&fromlen) < 0) { 349 (void) fprintf(stderr, "rshd: "); 350 perror("getpeername"); 351 _exit(1); 352 } 353 fd = STDIN_FILENO; 354 } 355 356 if (audit_settid(fd) != 0) { 357 perror("settid"); 358 exit(1); 359 } 360 361 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 362 sizeof (on)) < 0) 363 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 364 linger.l_onoff = 1; 365 linger.l_linger = 60; /* XXX */ 366 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&linger, 367 sizeof (linger)) < 0) 368 syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); 369 370 if ((tos != -1) && (setsockopt(fd, IPPROTO_IP, IP_TOS, (char *)&tos, 371 sizeof (tos)) < 0) && 372 (errno != ENOPROTOOPT)) { 373 syslog(LOG_ERR, "setsockopt (IP_TOS %d): %m"); 374 } 375 376 doit(dup(fd), &from, renvp); 377 return (0); 378 } 379 380 /* 381 * locale environments to be passed to shells. 382 */ 383 static char *localeenv[] = { 384 "LANG", 385 "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE", 386 "LC_MONETARY", "LC_MESSAGES", "LC_ALL", NULL}; 387 388 /* 389 * The following is for the environment variable list 390 * used in the call to execle(). envinit is declared here, 391 * but populated after the call to getpwnam(). 392 */ 393 static char *homedir; /* "HOME=" */ 394 static char *shell; /* "SHELL=" */ 395 static char *username; /* "USER=" */ 396 static char *tz; /* "TZ=" */ 397 398 static char homestr[] = "HOME="; 399 static char shellstr[] = "SHELL="; 400 static char userstr[] = "USER="; 401 static char tzstr[] = "TZ="; 402 403 static char **envinit; 404 #define PAM_ENV_ELIM 16 /* allow 16 PAM environment variables */ 405 #define USERNAME_LEN 16 /* maximum number of characters in user name */ 406 407 /* 408 * See PSARC opinion 1992/025 409 */ 410 static char userpath[] = "PATH=/usr/bin:"; 411 static char rootpath[] = "PATH=/usr/sbin:/usr/bin"; 412 413 static char cmdbuf[NCARGS+1]; 414 static char hostname [MAXHOSTNAMELEN + 1]; 415 static char locuser[USERNAME_LEN + 1]; 416 static char remuser[USERNAME_LEN + 1]; 417 418 #define KRB5_RECVAUTH_V5 5 419 #define SIZEOF_INADDR sizeof (struct in_addr) 420 421 #define MAX_REPOSITORY_LEN 255 422 static char repository[MAX_REPOSITORY_LEN]; 423 424 static char *kremuser; 425 static krb5_principal client = NULL; 426 427 static char remote_addr[64]; 428 static char local_addr[64]; 429 430 static void 431 doit(int f, struct sockaddr_storage *fromp, char **renvp) 432 { 433 char *cp; 434 435 struct passwd *pwd; 436 char *path; 437 char *tzenv; 438 struct spwd *shpwd; 439 struct stat statb; 440 char **lenvp; 441 442 krb5_error_code status; 443 int valid_checksum; 444 int cnt; 445 int sin_len; 446 struct sockaddr_in localaddr; 447 448 int s; 449 in_port_t port; 450 pid_t pid; 451 int pv[2], pw[2], px[2], cc; 452 char buf[RSHD_BUFSIZ]; 453 char sig; 454 int one = 1; 455 int v = 0; 456 int err = 0; 457 int idx = 0; 458 char **pam_env; 459 char abuf[INET6_ADDRSTRLEN]; 460 struct sockaddr_in *sin; 461 struct sockaddr_in6 *sin6; 462 int fromplen; 463 int homedir_len, shell_len, username_len, tz_len; 464 int no_name; 465 boolean_t bad_port; 466 int netf = 0; 467 468 (void) signal(SIGINT, SIG_DFL); 469 (void) signal(SIGQUIT, SIG_DFL); 470 (void) signal(SIGTERM, SIG_DFL); 471 (void) signal(SIGXCPU, SIG_DFL); 472 (void) signal(SIGXFSZ, SIG_DFL); 473 (void) sigset(SIGCHLD, SIG_IGN); 474 (void) signal(SIGPIPE, SIG_DFL); 475 (void) signal(SIGHUP, SIG_DFL); 476 477 #ifdef DEBUG 478 { int t = open("/dev/tty", 2); 479 if (t >= 0) { 480 (void) setsid(); 481 (void) close(t); 482 } 483 } 484 #endif 485 if (fromp->ss_family == AF_INET) { 486 sin = (struct sockaddr_in *)fromp; 487 port = ntohs((ushort_t)sin->sin_port); 488 fromplen = sizeof (struct sockaddr_in); 489 } else if (fromp->ss_family == AF_INET6) { 490 sin6 = (struct sockaddr_in6 *)fromp; 491 port = ntohs((ushort_t)sin6->sin6_port); 492 fromplen = sizeof (struct sockaddr_in6); 493 } else { 494 syslog(LOG_ERR, "wrong address family\n"); 495 exit(1); 496 } 497 498 if (fromp->ss_family == AF_INET6) { 499 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 500 struct in_addr ipv4_addr; 501 502 IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, &ipv4_addr); 503 (void) inet_ntop(AF_INET, &ipv4_addr, abuf, 504 sizeof (abuf)); 505 } else { 506 (void) inet_ntop(AF_INET6, &sin6->sin6_addr, abuf, 507 sizeof (abuf)); 508 } 509 } else if (fromp->ss_family == AF_INET) { 510 (void) inet_ntop(AF_INET, &sin->sin_addr, abuf, sizeof (abuf)); 511 } 512 513 sin_len = sizeof (struct sockaddr_in); 514 if (getsockname(f, (struct sockaddr *)&localaddr, &sin_len) < 0) { 515 perror("getsockname"); 516 exit(1); 517 } 518 519 netf = f; 520 521 bad_port = (port >= IPPORT_RESERVED || 522 port < (uint_t)(IPPORT_RESERVED/2)); 523 524 /* Get the name of the client side host to use later */ 525 no_name = (getnameinfo((const struct sockaddr *) fromp, fromplen, 526 hostname, sizeof (hostname), NULL, 0, 0) != 0); 527 528 if (bad_port || no_name != 0) { 529 /* 530 * If there is no host name available then use the 531 * IP address to identify the host in the PAM call 532 * below. Do the same if a bad port was used, to 533 * prevent untrustworthy authentication. 534 */ 535 (void) strlcpy(hostname, abuf, sizeof (hostname)); 536 } 537 538 if (no_name != 0) { 539 /* 540 * If the '-U' option was given on the cmd line, 541 * we must be able to lookup the hostname 542 */ 543 if (resolve_hostname) { 544 syslog(LOG_ERR, "rshd: Couldn't resolve your " 545 "address into a host name.\r\n Please " 546 "contact your net administrator"); 547 exit(1); 548 } 549 } else { 550 /* 551 * Even if getnameinfo() succeeded, we still have to check 552 * for spoofing. 553 */ 554 check_address("rshd", fromp, sin, sin6, abuf, hostname, 555 sizeof (hostname)); 556 } 557 558 if (!krb5auth_flag && bad_port) { 559 if (no_name) 560 syslog(LOG_NOTICE, "connection from %s - " 561 "bad port\n", abuf); 562 else 563 syslog(LOG_NOTICE, "connection from %s (%s) - " 564 "bad port\n", hostname, abuf); 565 exit(1); 566 } 567 568 (void) alarm(60); 569 port = 0; 570 for (;;) { 571 char c; 572 if ((cc = read(f, &c, 1)) != 1) { 573 if (cc < 0) 574 syslog(LOG_NOTICE, "read: %m"); 575 (void) shutdown(f, 1+1); 576 exit(1); 577 } 578 if (c == 0) 579 break; 580 port = port * 10 + c - '0'; 581 } 582 (void) alarm(0); 583 if (port != 0) { 584 int lport = 0; 585 struct sockaddr_storage ctl_addr; 586 int addrlen; 587 588 (void) memset(&ctl_addr, 0, sizeof (ctl_addr)); 589 addrlen = sizeof (ctl_addr); 590 if (getsockname(f, (struct sockaddr *)&ctl_addr, 591 &addrlen) < 0) { 592 syslog(LOG_ERR, "getsockname: %m"); 593 exit(1); 594 } 595 get_port: 596 /* 597 * 0 means that rresvport_addr() will bind to a port in 598 * the anonymous priviledged port range. 599 */ 600 if (krb5auth_flag) { 601 /* 602 * Kerberos does not support IPv6 yet. 603 */ 604 lport = IPPORT_RESERVED - 1; 605 } 606 s = rresvport_addr(&lport, &ctl_addr); 607 608 if (s < 0) { 609 syslog(LOG_ERR, "can't get stderr port: %m"); 610 exit(1); 611 } 612 if (!krb5auth_flag && (port >= IPPORT_RESERVED)) { 613 syslog(LOG_ERR, "2nd port not reserved\n"); 614 exit(1); 615 } 616 if (fromp->ss_family == AF_INET) { 617 sin->sin_port = htons((ushort_t)port); 618 } else if (fromp->ss_family == AF_INET6) { 619 sin6->sin6_port = htons((ushort_t)port); 620 } 621 if (connect(s, (struct sockaddr *)fromp, fromplen) < 0) { 622 if (errno == EADDRINUSE) { 623 (void) close(s); 624 goto get_port; 625 } 626 syslog(LOG_INFO, "connect second port: %m"); 627 exit(1); 628 } 629 } 630 (void) dup2(f, 0); 631 (void) dup2(f, 1); 632 (void) dup2(f, 2); 633 634 #ifdef DEBUG 635 syslog(LOG_NOTICE, "rshd: Client hostname = %s", hostname); 636 if (debug_port) 637 syslog(LOG_NOTICE, "rshd: Debug port is %d", debug_port); 638 if (krb5auth_flag > 0) 639 syslog(LOG_NOTICE, "rshd: Kerberos mode is ON"); 640 else 641 syslog(LOG_NOTICE, "rshd: Kerberos mode is OFF"); 642 #endif /* DEBUG */ 643 644 if (krb5auth_flag > 0) { 645 if ((status = recvauth(f, &valid_checksum))) { 646 syslog(LOG_ERR, gettext("Kerberos Authentication " 647 "failed \n")); 648 error("Authentication failed: %s\n", 649 error_message(status)); 650 (void) audit_rshd_fail("Kerberos Authentication " 651 "failed", hostname, remuser, locuser, cmdbuf); 652 exit(1); 653 } 654 655 if (checksum_required && !valid_checksum && 656 kcmd_protocol == KCMD_OLD_PROTOCOL) { 657 syslog(LOG_WARNING, "Client did not supply required" 658 " checksum--connection rejected."); 659 error("Client did not supply required" 660 "checksum--connection rejected.\n"); 661 (void) audit_rshd_fail("Client did not supply required" 662 " checksum--connection rejected.", hostname, 663 remuser, locuser, cmdbuf); /* BSM */ 664 goto signout; 665 } 666 667 /* 668 * Authentication has succeeded, we now need 669 * to check authorization. 670 * 671 * krb5_kuserok returns 1 if OK. 672 */ 673 if (client && krb5_kuserok(bsd_context, client, locuser)) { 674 auth_sent |= AUTH_KRB5; 675 } else { 676 syslog(LOG_ERR, "Principal %s (%s@%s) for local user " 677 "%s failed krb5_kuserok.\n", 678 kremuser, remuser, hostname, locuser); 679 } 680 } else { 681 getstr(netf, remuser, sizeof (remuser), "remuser"); 682 getstr(netf, locuser, sizeof (locuser), "locuser"); 683 getstr(netf, cmdbuf, sizeof (cmdbuf), "command"); 684 } 685 686 #ifdef DEBUG 687 syslog(LOG_NOTICE, "rshd: locuser = %s, remuser = %s, cmdbuf = %s", 688 locuser, remuser, cmdbuf); 689 #endif /* DEBUG */ 690 691 /* 692 * Note that there is no rsh conv functions at present. 693 */ 694 if (krb5auth_flag > 0) { 695 if ((err = pam_start("krsh", locuser, NULL, &pamh)) 696 != PAM_SUCCESS) { 697 syslog(LOG_ERR, "pam_start() failed: %s\n", 698 pam_strerror(0, err)); 699 exit(1); 700 } 701 } 702 else 703 { 704 if ((err = pam_start("rsh", locuser, NULL, &pamh)) 705 != PAM_SUCCESS) { 706 syslog(LOG_ERR, "pam_start() failed: %s\n", 707 pam_strerror(0, err)); 708 exit(1); 709 } 710 } 711 if ((err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS) { 712 syslog(LOG_ERR, "pam_set_item() failed: %s\n", 713 pam_strerror(pamh, err)); 714 exit(1); 715 } 716 if ((err = pam_set_item(pamh, PAM_RUSER, remuser)) != PAM_SUCCESS) { 717 syslog(LOG_ERR, "pam_set_item() failed: %s\n", 718 pam_strerror(pamh, err)); 719 exit(1); 720 } 721 722 pwd = getpwnam(locuser); 723 shpwd = getspnam(locuser); 724 if ((pwd == NULL) || (shpwd == NULL)) { 725 if (krb5auth_flag > 0) 726 syslog(LOG_ERR, "Principal %s (%s@%s) for local user " 727 "%s has no account.\n", kremuser, remuser, 728 hostname, locuser); 729 error("permission denied.\n"); 730 (void) audit_rshd_fail("Login incorrect", hostname, 731 remuser, locuser, cmdbuf); /* BSM */ 732 exit(1); 733 } 734 735 if (krb5auth_flag > 0) { 736 (void) snprintf(repository, sizeof (repository), 737 KRB5_REPOSITORY_NAME); 738 /* 739 * We currently only support special handling of the 740 * KRB5 PAM repository 741 */ 742 if (strlen(locuser) != 0) { 743 krb5_repository_data_t krb5_data; 744 pam_repository_t pam_rep_data; 745 746 krb5_data.principal = locuser; 747 krb5_data.flags = SUNW_PAM_KRB5_ALREADY_AUTHENTICATED; 748 749 pam_rep_data.type = repository; 750 pam_rep_data.scope = (void *)&krb5_data; 751 pam_rep_data.scope_len = sizeof (krb5_data); 752 753 (void) pam_set_item(pamh, PAM_REPOSITORY, 754 (void *)&pam_rep_data); 755 } 756 } 757 758 /* 759 * maintain 2.1 and 4.* and BSD semantics with anonymous rshd 760 */ 761 if (shpwd->sp_pwdp != 0 && *shpwd->sp_pwdp != '\0' && 762 (v = pam_authenticate(pamh, 0)) != PAM_SUCCESS) { 763 error("permission denied\n"); 764 (void) audit_rshd_fail("Permission denied", hostname, 765 remuser, locuser, cmdbuf); /* BSM */ 766 (void) pam_end(pamh, v); 767 exit(1); 768 } 769 770 if (krb5auth_flag > 0) { 771 if (require_encrypt && (!do_encrypt)) { 772 error("You must use encryption.\n"); 773 (void) audit_rshd_fail("You must use encryption.", 774 hostname, remuser, locuser, cmdbuf); /* BSM */ 775 goto signout; 776 } 777 778 if (!(auth_ok & auth_sent)) { 779 if (auth_sent) { 780 error("Another authentication mechanism " 781 "must be used to access this host.\n"); 782 (void) audit_rshd_fail("Another authentication" 783 " mechanism must be used to access" 784 " this host.\n", hostname, remuser, 785 locuser, cmdbuf); /* BSM */ 786 goto signout; 787 } else { 788 error("Permission denied.\n"); 789 (void) audit_rshd_fail("Permission denied.", 790 hostname, remuser, locuser, cmdbuf); 791 /* BSM */ 792 goto signout; 793 } 794 } 795 796 797 if (pwd->pw_uid && !access("/etc/nologin", F_OK)) { 798 error("Logins currently disabled.\n"); 799 (void) audit_rshd_fail("Logins currently disabled.", 800 hostname, remuser, locuser, cmdbuf); 801 goto signout; 802 } 803 804 /* Log access to account */ 805 if (pwd && (pwd->pw_uid == 0)) { 806 syslog(LOG_NOTICE, "Executing %s for user %s (%s@%s)" 807 " as ROOT", cmdbuf, 808 kremuser, remuser, hostname); 809 } 810 } 811 812 if ((v = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) { 813 switch (v) { 814 case PAM_NEW_AUTHTOK_REQD: 815 error("password expired\n"); 816 (void) audit_rshd_fail("Password expired", hostname, 817 remuser, locuser, cmdbuf); /* BSM */ 818 break; 819 case PAM_PERM_DENIED: 820 error("account expired\n"); 821 (void) audit_rshd_fail("Account expired", hostname, 822 remuser, locuser, cmdbuf); /* BSM */ 823 break; 824 case PAM_AUTHTOK_EXPIRED: 825 error("password expired\n"); 826 (void) audit_rshd_fail("Password expired", hostname, 827 remuser, locuser, cmdbuf); /* BSM */ 828 break; 829 default: 830 error("login incorrect\n"); 831 (void) audit_rshd_fail("Permission denied", hostname, 832 remuser, locuser, cmdbuf); /* BSM */ 833 break; 834 } 835 (void) pam_end(pamh, PAM_ABORT); 836 exit(1); 837 } 838 839 if (chdir(pwd->pw_dir) < 0) { 840 (void) chdir("/"); 841 #ifdef notdef 842 error("No remote directory.\n"); 843 844 exit(1); 845 #endif 846 } 847 848 /* 849 * XXX There is no session management currently being done 850 */ 851 852 (void) write(STDERR_FILENO, "\0", 1); 853 if (port || do_encrypt) { 854 if ((pipe(pv) < 0)) { 855 error("Can't make pipe.\n"); 856 (void) pam_end(pamh, PAM_ABORT); 857 exit(1); 858 } 859 if (do_encrypt) { 860 if (pipe(pw) < 0) { 861 error("Can't make pipe 2.\n"); 862 (void) pam_end(pamh, PAM_ABORT); 863 exit(1); 864 } 865 if (pipe(px) < 0) { 866 error("Can't make pipe 3.\n"); 867 (void) pam_end(pamh, PAM_ABORT); 868 exit(1); 869 } 870 } 871 pid = fork(); 872 if (pid == (pid_t)-1) { 873 error("Fork (to start shell) failed on server. " 874 "Please try again later.\n"); 875 (void) pam_end(pamh, PAM_ABORT); 876 exit(1); 877 } 878 if (pid) { 879 fd_set ready; 880 fd_set readfrom; 881 882 (void) close(STDIN_FILENO); 883 (void) close(STDOUT_FILENO); 884 (void) close(STDERR_FILENO); 885 (void) close(pv[1]); 886 if (do_encrypt) { 887 (void) close(pw[1]); 888 (void) close(px[0]); 889 } else { 890 (void) close(f); 891 } 892 893 (void) FD_ZERO(&readfrom); 894 895 FD_SET(pv[0], &readfrom); 896 if (do_encrypt) { 897 FD_SET(pw[0], &readfrom); 898 FD_SET(f, &readfrom); 899 } 900 if (port) 901 FD_SET(s, &readfrom); 902 903 /* read f (net), write to px[1] (child stdin) */ 904 /* read pw[0] (child stdout), write to f (net) */ 905 /* read s (alt. channel), signal child */ 906 /* read pv[0] (child stderr), write to s */ 907 if (ioctl(pv[0], FIONBIO, (char *)&one) == -1) 908 syslog(LOG_INFO, "ioctl FIONBIO: %m"); 909 if (do_encrypt && 910 ioctl(pw[0], FIONBIO, (char *)&one) == -1) 911 syslog(LOG_INFO, "ioctl FIONBIO: %m"); 912 do { 913 ready = readfrom; 914 if (select(FD_SETSIZE, &ready, NULL, 915 NULL, NULL) < 0) { 916 if (errno == EINTR) { 917 continue; 918 } else { 919 break; 920 } 921 } 922 /* 923 * Read from child stderr, write to net 924 */ 925 if (port && FD_ISSET(pv[0], &ready)) { 926 errno = 0; 927 cc = read(pv[0], buf, sizeof (buf)); 928 if (cc <= 0) { 929 (void) shutdown(s, 2); 930 FD_CLR(pv[0], &readfrom); 931 } else { 932 (void) deswrite(s, buf, cc, 1); 933 } 934 } 935 /* 936 * Read from alternate channel, signal child 937 */ 938 if (port && FD_ISSET(s, &ready)) { 939 if ((int)desread(s, &sig, 1, 1) <= 0) 940 FD_CLR(s, &readfrom); 941 else 942 (void) killpg(pid, sig); 943 } 944 /* 945 * Read from child stdout, write to net 946 */ 947 if (do_encrypt && FD_ISSET(pw[0], &ready)) { 948 errno = 0; 949 cc = read(pw[0], buf, sizeof (buf)); 950 if (cc <= 0) { 951 (void) shutdown(f, 2); 952 FD_CLR(pw[0], &readfrom); 953 } else { 954 (void) deswrite(f, buf, cc, 0); 955 } 956 } 957 /* 958 * Read from the net, write to child stdin 959 */ 960 if (do_encrypt && FD_ISSET(f, &ready)) { 961 errno = 0; 962 cc = desread(f, buf, sizeof (buf), 0); 963 if (cc <= 0) { 964 (void) close(px[1]); 965 FD_CLR(f, &readfrom); 966 } else { 967 int wcc; 968 wcc = write(px[1], buf, cc); 969 if (wcc == -1) { 970 /* 971 * pipe closed, 972 * don't read any 973 * more 974 * 975 * might check for 976 * EPIPE 977 */ 978 (void) close(px[1]); 979 FD_CLR(f, &readfrom); 980 } else if (wcc != cc) { 981 /* CSTYLED */ 982 syslog(LOG_INFO, gettext("only wrote %d/%d to child"), 983 wcc, cc); 984 } 985 } 986 } 987 } while ((port && FD_ISSET(s, &readfrom)) || 988 (port && FD_ISSET(pv[0], &readfrom)) || 989 (do_encrypt && FD_ISSET(f, &readfrom)) || 990 (do_encrypt && FD_ISSET(pw[0], &readfrom))); 991 #ifdef DEBUG 992 syslog(LOG_INFO, "Shell process completed."); 993 #endif /* DEBUG */ 994 if (ccache) 995 (void) pam_close_session(pamh, 0); 996 (void) pam_end(pamh, PAM_SUCCESS); 997 998 exit(0); 999 } /* End of Parent block */ 1000 1001 (void) setsid(); /* Should be the same as above. */ 1002 (void) close(pv[0]); 1003 (void) dup2(pv[1], 2); 1004 (void) close(pv[1]); 1005 if (port) 1006 (void) close(s); 1007 if (do_encrypt) { 1008 (void) close(f); 1009 (void) close(pw[0]); 1010 (void) close(px[1]); 1011 1012 (void) dup2(px[0], 0); 1013 (void) dup2(pw[1], 1); 1014 1015 (void) close(px[0]); 1016 (void) close(pw[1]); 1017 } 1018 } 1019 1020 if (*pwd->pw_shell == '\0') 1021 pwd->pw_shell = "/bin/sh"; 1022 if (!do_encrypt) 1023 (void) close(f); 1024 /* 1025 * write audit record before making uid switch 1026 */ 1027 (void) audit_rshd_success(hostname, remuser, locuser, cmdbuf); /* BSM */ 1028 1029 /* set the real (and effective) GID */ 1030 if (setgid(pwd->pw_gid) == -1) { 1031 error("Invalid gid.\n"); 1032 (void) pam_end(pamh, PAM_ABORT); 1033 exit(1); 1034 } 1035 1036 /* 1037 * Initialize the supplementary group access list. 1038 */ 1039 if (strlen(locuser) == 0) { 1040 error("No local user.\n"); 1041 (void) pam_end(pamh, PAM_ABORT); 1042 exit(1); 1043 } 1044 if (initgroups(locuser, pwd->pw_gid) == -1) { 1045 error("Initgroup failed.\n"); 1046 (void) pam_end(pamh, PAM_ABORT); 1047 exit(1); 1048 } 1049 1050 if ((v = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) { 1051 error("Insufficient credentials.\n"); 1052 (void) pam_end(pamh, v); 1053 exit(1); 1054 } 1055 1056 /* set the real (and effective) UID */ 1057 if (setuid(pwd->pw_uid) == -1) { 1058 error("Invalid uid.\n"); 1059 (void) pam_end(pamh, PAM_ABORT); 1060 exit(1); 1061 } 1062 1063 /* Change directory only after becoming the appropriate user. */ 1064 if (chdir(pwd->pw_dir) < 0) { 1065 (void) chdir("/"); 1066 if (krb5auth_flag > 0) { 1067 syslog(LOG_ERR, "Principal %s (%s@%s) for local user" 1068 " %s has no home directory.", 1069 kremuser, remuser, hostname, locuser); 1070 error("No remote directory.\n"); 1071 goto signout; 1072 } 1073 #ifdef notdef 1074 error("No remote directory.\n"); 1075 exit(1); 1076 #endif 1077 } 1078 1079 path = (pwd->pw_uid == 0) ? rootpath : userpath; 1080 1081 /* 1082 * Space for the following environ