1/*- 2 * Copyright (c) 1988, 1989, 1992, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 2002 Networks Associates Technology, Inc. 5 * All rights reserved. 6 * 7 * Portions of this software were developed for the FreeBSD Project by 8 * ThinkSec AS and NAI Labs, the Security Research Division of Network 9 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 10 * ("CBOSS"), as part of the DARPA CHATS research program. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 */ 40 41#ifndef lint 42__attribute__((__used__)) 43static const char copyright[] = 44"@(#) Copyright (c) 1988, 1989, 1992, 1993, 1994\n\ 45 The Regents of the University of California. All rights reserved.\n"; 46#endif /* not lint */ 47 48#ifndef lint 49#if 0 50static const char sccsid[] = "@(#)rshd.c 8.2 (Berkeley) 4/6/94"; 51#endif 52#endif /* not lint */ 53 54#include <sys/cdefs.h> 55__FBSDID("$FreeBSD: src/libexec/rshd/rshd.c,v 1.51 2005/05/11 02:41:39 jmallett Exp $"); 56 57/* 58 * remote shell server: 59 * [port]\0 60 * ruser\0 61 * luser\0 62 * command\0 63 * data 64 */ 65#include <sys/param.h> 66#include <sys/ioctl.h> 67#include <sys/time.h> 68#include <sys/socket.h> 69 70#include <netinet/in_systm.h> 71#include <netinet/in.h> 72#include <netinet/ip.h> 73#include <netinet/tcp.h> 74#include <arpa/inet.h> 75#include <netdb.h> 76 77#include <err.h> 78#include <errno.h> 79#include <fcntl.h> 80#ifndef __APPLE__ 81#include <libutil.h> 82#endif 83#include <paths.h> 84#include <pwd.h> 85#include <signal.h> 86#include <stdarg.h> 87#include <stdio.h> 88#include <stdlib.h> 89#include <string.h> 90#include <syslog.h> 91#include <unistd.h> 92#ifndef __APPLE__ 93#include <login_cap.h> 94#endif 95 96#ifdef __APPLE__ 97#include <TargetConditionals.h> 98#endif 99 100#if !TARGET_OS_EMBEDDED 101#include <security/pam_appl.h> 102#include <security/openpam.h> 103#endif 104 105#include <sys/wait.h> 106 107#if !TARGET_OS_EMBEDDED 108static struct pam_conv pamc = { openpam_nullconv, NULL }; 109static pam_handle_t *pamh; 110static int pam_err; 111#endif 112 113#define PAM_END { \ 114 if ((pam_err = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \ 115 syslog(LOG_ERR|LOG_AUTH, "pam_setcred(): %s", pam_strerror(pamh, pam_err)); \ 116 if ((pam_err = pam_close_session(pamh,0)) != PAM_SUCCESS) \ 117 syslog(LOG_ERR|LOG_AUTH, "pam_close_session(): %s", pam_strerror(pamh, pam_err)); \ 118 if ((pam_err = pam_end(pamh, pam_err)) != PAM_SUCCESS) \ 119 syslog(LOG_ERR|LOG_AUTH, "pam_end(): %s", pam_strerror(pamh, pam_err)); \ 120} 121 122int keepalive = 1; 123int check_all; 124int log_success; /* If TRUE, log all successful accesses */ 125int sent_null; 126int no_delay; 127 128#ifdef __APPLE__ 129#define __printf0like(a,b) 130#endif 131 132void doit(struct sockaddr *); 133static void rshd_errx(int, const char *, ...) __printf0like(2, 3); 134void getstr(char *, int, const char *); 135int local_domain(char *); 136char *topdomain(char *); 137void usage(void); 138 139char slash[] = "/"; 140char bshell[] = _PATH_BSHELL; 141 142#if defined(KERBEROS) 143#include <kerberosIV/des.h> 144#include <kerberosIV/krb.h> 145#define VERSION_SIZE 9 146#define SECURE_MESSAGE "This rsh session is using DES encryption for all transmissions.\r\n" 147#define OPTIONS "alnkvxL" 148char authbuf[sizeof(AUTH_DAT)]; 149char tickbuf[sizeof(KTEXT_ST)]; 150int doencrypt, use_kerberos, vacuous; 151Key_schedule schedule; 152#else 153#define OPTIONS "aDLln" 154#endif 155 156int 157main(int argc, char *argv[]) 158{ 159 extern int __check_rhosts_file; 160 struct linger linger; 161 socklen_t fromlen; 162 int ch, on = 1; 163 struct sockaddr_storage from; 164 165 openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON); 166 167 opterr = 0; 168 while ((ch = getopt(argc, argv, OPTIONS)) != -1) 169 switch (ch) { 170 case 'a': 171 /* ignored for compatibility */ 172 check_all = 1; 173 break; 174 case 'l': 175 __check_rhosts_file = 0; 176 break; 177 case 'n': 178 keepalive = 0; 179 break; 180#if defined(KERBEROS) 181 case 'k': 182 use_kerberos = 1; 183 break; 184 case 'v': 185 vacuous = 1; 186 break; 187#if defined(CRYPT) 188 case 'x': 189 doencrypt = 1; 190 break; 191#endif /* CRYPT */ 192#endif /* KERBEROS */ 193 case 'D': 194 no_delay = 1; 195 break; 196 case 'L': 197 log_success = 1; 198 break; 199 case '?': 200 default: 201 usage(); 202 break; 203 } 204 205 argc -= optind; 206 argv += optind; 207 208#if defined(KERBEROS) 209 if (use_kerberos && vacuous) { 210 syslog(LOG_ERR, "only one of -k and -v allowed"); 211 exit(2); 212 } 213#if defined(CRYPT) 214 if (doencrypt && !use_kerberos) { 215 syslog(LOG_ERR, "-k is required for -x"); 216 exit(2); 217 } 218#endif /* CRYPT */ 219#endif /* KERBEROS */ 220 221 fromlen = sizeof (from); 222 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 223 syslog(LOG_ERR, "getpeername: %m"); 224 exit(1); 225 } 226 if (keepalive && 227 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 228 sizeof(on)) < 0) 229 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 230 linger.l_onoff = 1; 231 linger.l_linger = 60; /* XXX */ 232 if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, 233 sizeof (linger)) < 0) 234 syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); 235 if (no_delay && 236 setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) 237 syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m"); 238 doit((struct sockaddr *)&from); 239 /* NOTREACHED */ 240 return(0); 241} 242 243#ifdef __APPLE__ 244char username[20] = "USER="; 245char homedir[64] = "HOME="; 246char shell[64] = "SHELL="; 247char path[100] = "PATH="; 248char *envinit[] = 249 {homedir, shell, path, username, 0}; 250#endif 251extern char **environ; 252 253void 254doit(struct sockaddr *fromp) 255{ 256 extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */ 257 struct passwd *pwd; 258 u_short port; 259 fd_set ready, readfrom; 260 int cc, fd, nfd, pv[2], pid, s; 261 int one = 1; 262 const char *cp, *errorstr; 263 char sig, buf[BUFSIZ]; 264 char *cmdbuf, luser[16], ruser[16]; 265 char rhost[2 * MAXHOSTNAMELEN + 1]; 266 char numericname[INET6_ADDRSTRLEN]; 267 int af, srcport; 268 int maxcmdlen; 269#ifndef __APPLE__ 270 login_cap_t *lc; 271#else 272 struct hostent *hp; 273 char *hostname, *errorhost = NULL; 274#endif 275 276 maxcmdlen = (int)sysconf(_SC_ARG_MAX); 277 if (maxcmdlen <= 0 || (cmdbuf = malloc(maxcmdlen)) == NULL) 278 exit(1); 279 280#if defined(KERBEROS) 281 AUTH_DAT *kdata = (AUTH_DAT *) NULL; 282 KTEXT ticket = (KTEXT) NULL; 283 char instance[INST_SZ], version[VERSION_SIZE]; 284 struct sockaddr_in fromaddr; 285 int rc; 286 long authopts; 287 int pv1[2], pv2[2]; 288 fd_set wready, writeto; 289 290 fromaddr = *fromp; 291#endif /* KERBEROS */ 292 293 (void) signal(SIGINT, SIG_DFL); 294 (void) signal(SIGQUIT, SIG_DFL); 295 (void) signal(SIGTERM, SIG_DFL); 296 af = fromp->sa_family; 297 srcport = ntohs(*((in_port_t *)&fromp->sa_data)); 298 if (af == AF_INET) { 299 inet_ntop(af, &((struct sockaddr_in *)fromp)->sin_addr, 300 numericname, sizeof numericname); 301 } else if (af == AF_INET6) { 302 inet_ntop(af, &((struct sockaddr_in6 *)fromp)->sin6_addr, 303 numericname, sizeof numericname); 304 } else { 305 syslog(LOG_ERR, "malformed \"from\" address (af %d)", af); 306 exit(1); 307 } 308#ifdef IP_OPTIONS 309 if (af == AF_INET) { 310 u_char optbuf[BUFSIZ/3]; 311 socklen_t optsize = sizeof(optbuf), ipproto, i; 312 struct protoent *ip; 313 314 if ((ip = getprotobyname("ip")) != NULL) 315 ipproto = ip->p_proto; 316 else 317 ipproto = IPPROTO_IP; 318 if (!getsockopt(0, ipproto, IP_OPTIONS, optbuf, &optsize) && 319 optsize != 0) { 320 for (i = 0; i < optsize; ) { 321 u_char c = optbuf[i]; 322 if (c == IPOPT_LSRR || c == IPOPT_SSRR) { 323 syslog(LOG_NOTICE, 324 "connection refused from %s with IP option %s", 325 numericname, 326 c == IPOPT_LSRR ? "LSRR" : "SSRR"); 327 exit(1); 328 } 329 if (c == IPOPT_EOL) 330 break; 331 i += (c == IPOPT_NOP) ? 1 : optbuf[i+1]; 332 } 333 } 334 } 335#endif 336 337#if defined(KERBEROS) 338 if (!use_kerberos) 339#endif 340 if (srcport >= IPPORT_RESERVED || 341 srcport < IPPORT_RESERVED/2) { 342 syslog(LOG_NOTICE|LOG_AUTH, 343 "connection from %s on illegal port %u", 344 numericname, 345 srcport); 346 exit(1); 347 } 348 349 (void) alarm(60); 350 port = 0; 351 s = 0; /* not set or used if port == 0 */ 352 for (;;) { 353 char c; 354 if ((cc = read(STDIN_FILENO, &c, 1)) != 1) { 355 if (cc < 0) 356 syslog(LOG_NOTICE, "read: %m"); 357 shutdown(0, SHUT_RDWR); 358 exit(1); 359 } 360 if (c == 0) 361 break; 362 port = port * 10 + c - '0'; 363 } 364 365 (void) alarm(0); 366 if (port != 0) { 367 int lport = IPPORT_RESERVED - 1; 368 s = rresvport_af(&lport, af); 369 if (s < 0) { 370 syslog(LOG_ERR, "can't get stderr port: %m"); 371 exit(1); 372 } 373#if defined(KERBEROS) 374 if (!use_kerberos) 375#endif 376 if (port >= IPPORT_RESERVED || 377 port < IPPORT_RESERVED/2) { 378 syslog(LOG_NOTICE|LOG_AUTH, 379 "2nd socket from %s on unreserved port %u", 380 numericname, 381 port); 382 exit(1); 383 } 384 *((in_port_t *)&fromp->sa_data) = htons(port); 385 if (connect(s, fromp, fromp->sa_len) < 0) { 386 syslog(LOG_INFO, "connect second port %d: %m", port); 387 exit(1); 388 } 389 } 390 391#if defined(KERBEROS) 392 if (vacuous) { 393 error("rshd: remote host requires Kerberos authentication\n"); 394 exit(1); 395 } 396#endif 397 398 errorstr = NULL; 399#ifndef __APPLE__ 400 realhostname_sa(rhost, sizeof(rhost) - 1, fromp, fromp->sa_len); 401 rhost[sizeof(rhost) - 1] = '\0'; 402 /* XXX truncation! */ 403#else 404 errorstr = NULL; 405 hp = gethostbyaddr((char *)&((struct sockaddr_in *)fromp)->sin_addr, sizeof (struct in_addr), 406 ((struct sockaddr_in *)fromp)->sin_family); 407 if (hp) { 408 /* 409 * If name returned by gethostbyaddr is in our domain, 410 * attempt to verify that we haven't been fooled by someone 411 * in a remote net; look up the name and check that this 412 * address corresponds to the name. 413 */ 414 hostname = hp->h_name; 415#if defined(KERBEROS) 416 if (!use_kerberos) 417#endif 418 if (check_all || local_domain(hp->h_name)) { 419 strncpy(rhost, hp->h_name, sizeof(rhost) - 1); 420 rhost[sizeof(rhost) - 1] = 0; 421 errorhost = rhost; 422 hp = gethostbyname(rhost); 423 if (hp == NULL) { 424 syslog(LOG_INFO, 425 "Couldn't look up address for %s", 426 rhost); 427 errorstr = 428 "Couldn't look up address for your host (%s)\n"; 429 hostname = inet_ntoa(((struct sockaddr_in *)fromp)->sin_addr); 430 } else for (; ; hp->h_addr_list++) { 431 if (hp->h_addr_list[0] == NULL) { 432 syslog(LOG_NOTICE, 433 "Host addr %s not listed for host %s", 434 inet_ntoa(((struct sockaddr_in *)fromp)->sin_addr), 435 hp->h_name); 436 errorstr = 437 "Host address mismatch for %s\n"; 438 hostname = inet_ntoa(((struct sockaddr_in *)fromp)->sin_addr); 439 break; 440 } 441 if (!bcmp(hp->h_addr_list[0], 442 (caddr_t)&((struct sockaddr_in *)fromp)->sin_addr, 443 sizeof(((struct sockaddr_in *)fromp)->sin_addr))) { 444 hostname = hp->h_name; 445 break; 446 } 447 } 448 } 449 } else 450 errorhost = hostname = inet_ntoa(((struct sockaddr_in *)fromp)->sin_addr); 451 452#if defined(KERBEROS) 453 if (use_kerberos) { 454 kdata = (AUTH_DAT *) authbuf; 455 ticket = (KTEXT) tickbuf; 456 authopts = 0L; 457 strcpy(instance, "*"); 458 version[VERSION_SIZE - 1] = '\0'; 459#if defined(CRYPT) 460 if (doencrypt) { 461 struct sockaddr_in local_addr; 462 rc = sizeof(local_addr); 463 if (getsockname(0, (struct sockaddr *)&local_addr, 464 &rc) < 0) { 465 syslog(LOG_ERR, "getsockname: %m"); 466 error("rshd: getsockname: %m"); 467 exit(1); 468 } 469 authopts = KOPT_DO_MUTUAL; 470 rc = krb_recvauth(authopts, 0, ticket, 471 "rcmd", instance, &fromaddr, 472 &local_addr, kdata, "", schedule, 473 version); 474 des_set_key(kdata->session, schedule); 475 } else 476#endif /* CRYPT */ 477 rc = krb_recvauth(authopts, 0, ticket, "rcmd", 478 instance, &fromaddr, 479 (struct sockaddr_in *) 0, 480 kdata, "", (bit_64 *) 0, version); 481 if (rc != KSUCCESS) { 482 error("Kerberos authentication failure: %s\n", 483 krb_err_txt[rc]); 484 exit(1); 485 } 486 } else 487#endif /* KERBEROS */ 488#endif 489 490 (void) alarm(60); 491 getstr(ruser, sizeof(ruser), "ruser"); 492 getstr(luser, sizeof(luser), "luser"); 493 getstr(cmdbuf, maxcmdlen, "command"); 494 (void) alarm(0); 495#if !TARGET_OS_EMBEDDED 496 pam_err = pam_start("rshd", luser, &pamc, &pamh); 497 if (pam_err != PAM_SUCCESS) { 498 syslog(LOG_ERR|LOG_AUTH, "pam_start(): %s", 499 pam_strerror(pamh, pam_err)); 500 rshd_errx(1, "Login incorrect."); 501 } 502 503 if ((pam_err = pam_set_item(pamh, PAM_RUSER, ruser)) != PAM_SUCCESS || 504 (pam_err = pam_set_item(pamh, PAM_RHOST, rhost) != PAM_SUCCESS)) { 505 syslog(LOG_ERR|LOG_AUTH, "pam_set_item(): %s", 506 pam_strerror(pamh, pam_err)); 507 rshd_errx(1, "Login incorrect."); 508 } 509 510 pam_err = pam_authenticate(pamh, 0); 511 if (pam_err == PAM_SUCCESS) { 512 if ((pam_err = pam_get_user(pamh, &cp, NULL)) == PAM_SUCCESS) { 513 strncpy(luser, cp, sizeof(luser)); 514 luser[sizeof(luser) - 1] = '\0'; 515 /* XXX truncation! */ 516 } 517 pam_err = pam_acct_mgmt(pamh, 0); 518 } 519 if (pam_err != PAM_SUCCESS) { 520 syslog(LOG_INFO|LOG_AUTH, 521 "%s@%s as %s: permission denied (%s). cmd='%.80s'", 522 ruser, rhost, luser, pam_strerror(pamh, pam_err), cmdbuf); 523 rshd_errx(1, "Login incorrect."); 524 } 525#endif 526 setpwent(); 527 pwd = getpwnam(luser); 528 if (pwd == NULL) { 529 syslog(LOG_INFO|LOG_AUTH, 530 "%s@%s as %s: unknown login. cmd='%.80s'", 531 ruser, rhost, luser, cmdbuf); 532 if (errorstr == NULL) 533 errorstr = "Login incorrect."; 534 rshd_errx(1, errorstr, rhost); 535 } 536 537#ifndef __APPLE__ 538 lc = login_getpwclass(pwd); 539 if (pwd->pw_uid) 540 auth_checknologin(lc); 541#endif 542 543 if (chdir(pwd->pw_dir) < 0) { 544 if (chdir("/") < 0 || 545#ifndef __APPLE__ 546 login_getcapbool(lc, "requirehome", !!pwd->pw_uid)) { 547#else 548 0) { 549#endif /* __APPLE__ */ 550#ifdef notdef 551 syslog(LOG_INFO|LOG_AUTH, 552 "%s@%s as %s: no home directory. cmd='%.80s'", 553 ruser, rhost, luser, cmdbuf); 554 rshd_errx(0, "No remote home directory."); 555#endif 556 } 557 pwd->pw_dir = slash; 558 } 559 560#if defined(KERBEROS) 561 if (use_kerberos) { 562 if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') { 563 if (kuserok(kdata, luser) != 0) { 564 syslog(LOG_INFO|LOG_AUTH, 565 "Kerberos rsh denied to %s.%s@%s", 566 kdata->pname, kdata->pinst, kdata->prealm); 567 error("Permission denied.\n"); 568 exit(1); 569 } 570 } 571 } else 572#endif 573 574#ifdef __APPLE__ 575 if (errorstr || 576 (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && 577 iruserok(((struct sockaddr_in *)fromp)->sin_addr.s_addr, 578#if TARGET_OS_EMBEDDED 579 // rdar://problem/5381734 580 0, 581#else 582 pwd->pw_uid == 0, 583#endif 584 ruser, luser) < 0)) { 585 if (__rcmd_errstr) 586 syslog(LOG_INFO|LOG_AUTH, 587 "%s@%s as %s: permission denied (%s). cmd='%.80s'", 588 ruser, rhost, luser, __rcmd_errstr, 589 cmdbuf); 590 else 591 syslog(LOG_INFO|LOG_AUTH, 592 "%s@%s as %s: permission denied. cmd='%.80s'", 593 ruser, rhost, luser, cmdbuf); 594 if (errorstr == NULL) 595 errorstr = "Permission denied."; 596 rshd_errx(1, errorstr, errorhost); 597 } 598 599 if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) { 600 rshd_errx(1, "Logins currently disabled."); 601 } 602#else 603 if (lc != NULL && fromp->sa_family == AF_INET) { /*XXX*/ 604 char remote_ip[MAXHOSTNAMELEN]; 605 606 strncpy(remote_ip, numericname, 607 sizeof(remote_ip) - 1); 608 remote_ip[sizeof(remote_ip) - 1] = 0; 609 /* XXX truncation! */ 610 if (!auth_hostok(lc, rhost, remote_ip)) { 611 syslog(LOG_INFO|LOG_AUTH, 612 "%s@%s as %s: permission denied (%s). cmd='%.80s'", 613 ruser, rhost, luser, __rcmd_errstr, 614 cmdbuf); 615 rshd_errx(1, "Login incorrect."); 616 } 617 if (!auth_timeok(lc, time(NULL))) 618 rshd_errx(1, "Logins not available right now"); 619 } 620 621 /* 622 * PAM modules might add supplementary groups in 623 * pam_setcred(), so initialize them first. 624 * But we need to open the session as root. 625 */ 626 if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) { 627 syslog(LOG_ERR, "setusercontext: %m"); 628 exit(1); 629 } 630#endif /* !__APPLE__ */ 631 632#if !TARGET_OS_EMBEDDED 633 if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS) { 634 syslog(LOG_ERR, "pam_open_session: %s", pam_strerror(pamh, pam_err)); 635 } else if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) { 636 syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, pam_err)); 637 } 638#endif 639 (void) write(STDERR_FILENO, "\0", 1); 640 sent_null = 1; 641 642 if (port) { 643 if (pipe(pv) < 0) 644 rshd_errx(1, "Can't make pipe."); 645#if defined(KERBEROS) && defined(CRYPT) 646 if (doencrypt) { 647 if (pipe(pv1) < 0) 648 rshd_errx(1, "Can't make 2nd pipe."); 649 if (pipe(pv2) < 0) 650 rshd_errx(1, "Can't make 3rd pipe."); 651 } 652#endif /* KERBEROS && CRYPT */ 653 pid = fork(); 654 if (pid == -1) 655 rshd_errx(1, "Can't fork; try again."); 656 if (pid) { 657#if defined(KERBEROS) && defined(CRYPT) 658 if (doencrypt) { 659 static char msg[] = SECURE_MESSAGE; 660 (void) close(pv1[1]); 661 (void) close(pv2[1]); 662 des_write(s, msg, sizeof(msg) - 1); 663 664 } else 665#endif /* KERBEROS && CRYPT */ 666 (void) close(0); 667 (void) close(1); 668 (void) close(2); 669 (void) close(pv[1]); 670 671 FD_ZERO(&readfrom); 672 FD_SET(s, &readfrom); 673 FD_SET(pv[0], &readfrom); 674 if (pv[0] > s) 675 nfd = pv[0]; 676 else 677 nfd = s; 678#if defined(KERBEROS) && defined(CRYPT) 679 if (doencrypt) { 680 FD_ZERO(&writeto); 681 FD_SET(pv2[0], &writeto); 682 FD_SET(pv1[0], &readfrom); 683 684 nfd = MAX(nfd, pv2[0]); 685 nfd = MAX(nfd, pv1[0]); 686 } else 687#endif /* KERBEROS && CRYPT */ 688 ioctl(pv[0], FIONBIO, (char *)&one); 689 690 /* should set s nbio! */ 691 nfd++; 692 do { 693 ready = readfrom; 694#if defined(KERBEROS) && defined(CRYPT) 695 if (doencrypt) { 696 wready = writeto; 697 if (select(nfd, &ready, 698 &wready, (fd_set *) 0, 699 (struct timeval *) 0) < 0) 700 break; 701 } else 702#endif /* KERBEROS && CRYPT */ 703 if (select(nfd, &ready, (fd_set *)0, 704 (fd_set *)0, (struct timeval *)0) < 0) 705 break; 706 if (FD_ISSET(s, &ready)) { 707 int ret; 708#if defined(KERBEROS) && defined(CRYPT) 709 if (doencrypt) 710 ret = des_read(s, &sig, 1); 711 else 712#endif /* KERBEROS && CRYPT */ 713 ret = read(s, &sig, 1); 714 if (ret <= 0) 715 FD_CLR(s, &readfrom); 716 else 717 killpg(pid, sig); 718 } 719 if (FD_ISSET(pv[0], &ready)) { 720 errno = 0; 721 cc = read(pv[0], buf, sizeof(buf)); 722 if (cc <= 0) { 723 shutdown(s, SHUT_RDWR); 724 FD_CLR(pv[0], &readfrom); 725 } else { 726#if defined(KERBEROS) && defined(CRYPT) 727 if (doencrypt) 728 (void) 729 des_write(s, buf, cc); 730 else 731#endif /* KERBEROS && CRYPT */ 732 (void)write(s, buf, cc); 733 } 734 } 735#if defined(KERBEROS) && defined(CRYPT) 736 if (doencrypt && FD_ISSET(pv1[0], &ready)) { 737 errno = 0; 738 cc = read(pv1[0], buf, sizeof(buf)); 739 if (cc <= 0) { 740 shutdown(pv1[0], 1+1); 741 FD_CLR(pv1[0], &readfrom); 742 } else 743 (void) des_write(STDOUT_FILENO, 744 buf, cc); 745 } 746 747 if (doencrypt && FD_ISSET(pv2[0], &wready)) { 748 errno = 0; 749 cc = des_read(STDIN_FILENO, 750 buf, sizeof(buf)); 751 if (cc <= 0) { 752 shutdown(pv2[0], 1+1); 753 FD_CLR(pv2[0], &writeto); 754 } else 755 (void) write(pv2[0], buf, cc); 756 } 757#endif /* KERBEROS && CRYPT */ 758 759 } while (FD_ISSET(s, &readfrom) || 760#if defined(KERBEROS) && defined(CRYPT) 761 (doencrypt && FD_ISSET(pv1[0], &readfrom)) || 762#endif /* KERBEROS && CRYPT */ 763 FD_ISSET(pv[0], &readfrom)); 764#if !TARGET_OS_EMBEDDED 765 PAM_END; 766#endif 767 exit(0); 768 } 769#ifdef __APPLE__ 770 // rdar://problem/4485794 771 setpgid(0, getpid()); 772#endif 773 (void) close(s); 774 (void) close(pv[0]); 775#if defined(KERBEROS) && defined(CRYPT) 776 if (doencrypt) { 777 close(pv1[0]); close(pv2[0]); 778 dup2(pv1[1], 1); 779 dup2(pv2[1], 0); 780 close(pv1[1]); 781 close(pv2[1]); 782 } 783#endif /* KERBEROS && CRYPT */ 784 dup2(pv[1], 2); 785 close(pv[1]); 786 } 787#ifndef __APPLE__ 788 else { 789 pid = fork(); 790 if (pid == -1) 791 rshd_errx(1, "Can't fork; try again."); 792 if (pid) { 793 /* Parent. */ 794 while (wait(NULL) > 0 || errno == EINTR) 795 /* nothing */ ; 796 PAM_END; 797 exit(0); 798 } 799 } 800#endif 801 802 for (fd = getdtablesize(); fd > 2; fd--) { 803#ifdef __APPLE__ 804 (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 805#else 806 (void) close(fd); 807#endif 808 } 809 if (setsid() == -1) 810 syslog(LOG_ERR, "setsid() failed: %m"); 811 if (setlogin(pwd->pw_name) < 0) 812 syslog(LOG_ERR, "setlogin() failed: %m"); 813 814 if (*pwd->pw_shell == '\0') 815 pwd->pw_shell = bshell; 816#ifdef __APPLE__ 817 (void) setgid((gid_t)pwd->pw_gid); 818 initgroups(pwd->pw_name, pwd->pw_gid); 819 (void) setuid((uid_t)pwd->pw_uid); 820 821 environ = envinit; 822 strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); 823 strcat(path, _PATH_DEFPATH); 824 strncat(shell, pwd->pw_shell, sizeof(shell)-7); 825 strncat(username, pwd->pw_name, sizeof(username)-6); 826#endif 827#if !TARGET_OS_EMBEDDED 828 (void) pam_setenv(pamh, "HOME", pwd->pw_dir, 1); 829 (void) pam_setenv(pamh, "SHELL", pwd->pw_shell, 1); 830 (void) pam_setenv(pamh, "USER", pwd->pw_name, 1); 831 (void) pam_setenv(pamh, "PATH", _PATH_DEFPATH, 1); 832 environ = pam_getenvlist(pamh); 833 (void) pam_end(pamh, pam_err); 834#endif 835 cp = strrchr(pwd->pw_shell, '/'); 836 if (cp) 837 cp++; 838 else 839 cp = pwd->pw_shell; 840 841#ifndef __APPLE__ 842 if (setusercontext(lc, pwd, pwd->pw_uid, 843 LOGIN_SETALL & ~LOGIN_SETGROUP) < 0) { 844 syslog(LOG_ERR, "setusercontext(): %m"); 845 exit(1); 846 } 847 login_close(lc); 848#endif 849 endpwent(); 850 if (log_success || pwd->pw_uid == 0) { 851#if defined(KERBEROS) 852 if (use_kerberos) 853 syslog(LOG_INFO|LOG_AUTH, 854 "Kerberos shell from %s.%s@%s on %s as %s, cmd='%.80s'", 855 kdata->pname, kdata->pinst, kdata->prealm, 856 hostname, luser, cmdbuf); 857 else 858#endif /* KERBEROS */ 859 syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'", 860 ruser, rhost, luser, cmdbuf); 861 } 862 execl(pwd->pw_shell, cp, "-c", cmdbuf, (char *)NULL); 863 err(1, "%s", pwd->pw_shell); 864 exit(1); 865} 866 867/* 868 * Report error to client. Note: can't be used until second socket has 869 * connected to client, or older clients will hang waiting for that 870 * connection first. 871 */ 872 873static void 874rshd_errx(int errcode, const char *fmt, ...) 875{ 876 va_list ap; 877 878 va_start(ap, fmt); 879 880 if (sent_null == 0) 881 write(STDERR_FILENO, "\1", 1); 882 883 verrx(errcode, fmt, ap); 884 /* NOTREACHED */ 885} 886 887void 888getstr(char *buf, int cnt, const char *error) 889{ 890 char c; 891 892 do { 893 if (read(STDIN_FILENO, &c, 1) != 1) 894 exit(1); 895 *buf++ = c; 896 if (--cnt == 0) 897 rshd_errx(1, "%s too long", error); 898 } while (c != 0); 899} 900 901/* 902 * Check whether host h is in our local domain, 903 * defined as sharing the last two components of the domain part, 904 * or the entire domain part if the local domain has only one component. 905 * If either name is unqualified (contains no '.'), 906 * assume that the host is local, as it will be 907 * interpreted as such. 908 */ 909int 910local_domain(char *h) 911{ 912 char localhost[MAXHOSTNAMELEN]; 913 char *p1, *p2; 914 915 localhost[0] = 0; 916 (void) gethostname(localhost, sizeof(localhost) - 1); 917 localhost[sizeof(localhost) - 1] = '\0'; 918 /* XXX truncation! */ 919 p1 = topdomain(localhost); 920 p2 = topdomain(h); 921 if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 922 return (1); 923 return (0); 924} 925 926char * 927topdomain(char *h) 928{ 929 char *p, *maybe = NULL; 930 int dots = 0; 931 932 for (p = h + strlen(h); p >= h; p--) { 933 if (*p == '.') { 934 if (++dots == 2) 935 return (p); 936 maybe = p; 937 } 938 } 939 return (maybe); 940} 941 942void 943usage(void) 944{ 945 946 syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS); 947 exit(2); 948} 949