121176Sdist /* 221176Sdist * Copyright (c) 1983 Regents of the University of California. 321176Sdist * All rights reserved. The Berkeley software License Agreement 421176Sdist * specifies the terms and conditions for redistribution. 521176Sdist */ 621176Sdist 76454Swnj #ifndef lint 821176Sdist char copyright[] = 921176Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 1021176Sdist All rights reserved.\n"; 1121176Sdist #endif not lint 126454Swnj 1321176Sdist #ifndef lint 14*30265Smckusick static char sccsid[] = "@(#)rshd.c 5.8 (Berkeley) 12/09/86"; 1521176Sdist #endif not lint 1621176Sdist 1716370Skarels /* 1816370Skarels * remote shell server: 1916370Skarels * remuser\0 2016370Skarels * locuser\0 2116370Skarels * command\0 2216370Skarels * data 2316370Skarels */ 246454Swnj #include <sys/ioctl.h> 256454Swnj #include <sys/param.h> 266454Swnj #include <sys/socket.h> 2727901Slepreau #include <sys/time.h> 289212Ssam 299212Ssam #include <netinet/in.h> 309212Ssam 3124903Sbloom #include <arpa/inet.h> 3224903Sbloom 339212Ssam #include <stdio.h> 346454Swnj #include <errno.h> 356454Swnj #include <pwd.h> 366454Swnj #include <signal.h> 378380Ssam #include <netdb.h> 3817187Sralph #include <syslog.h> 396454Swnj 406454Swnj int errno; 4127901Slepreau char *index(), *rindex(), *strncat(); 4227901Slepreau /*VARARGS1*/ 436454Swnj int error(); 4416370Skarels 4527901Slepreau /*ARGSUSED*/ 466454Swnj main(argc, argv) 476454Swnj int argc; 486454Swnj char **argv; 496454Swnj { 5017156Ssam struct linger linger; 5117156Ssam int on = 1, fromlen; 526454Swnj struct sockaddr_in from; 536454Swnj 5424851Seric openlog("rsh", LOG_PID | LOG_ODELAY, LOG_DAEMON); 5516370Skarels fromlen = sizeof (from); 5616370Skarels if (getpeername(0, &from, &fromlen) < 0) { 5716370Skarels fprintf(stderr, "%s: ", argv[0]); 5816370Skarels perror("getpeername"); 5916370Skarels _exit(1); 608380Ssam } 6127901Slepreau if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 6227901Slepreau sizeof (on)) < 0) 6317187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 6417156Ssam linger.l_onoff = 1; 6517156Ssam linger.l_linger = 60; /* XXX */ 6627901Slepreau if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, 6727901Slepreau sizeof (linger)) < 0) 6817187Sralph syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); 6916370Skarels doit(dup(0), &from); 706454Swnj } 716454Swnj 726454Swnj char username[20] = "USER="; 736454Swnj char homedir[64] = "HOME="; 746454Swnj char shell[64] = "SHELL="; 756454Swnj char *envinit[] = 766454Swnj {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", username, 0}; 776454Swnj char **environ; 786454Swnj 796454Swnj doit(f, fromp) 806454Swnj int f; 816454Swnj struct sockaddr_in *fromp; 826454Swnj { 836454Swnj char cmdbuf[NCARGS+1], *cp; 846454Swnj char locuser[16], remuser[16]; 856454Swnj struct passwd *pwd; 8627901Slepreau int s; 878380Ssam struct hostent *hp; 8825985Skarels char *hostname; 896454Swnj short port; 906454Swnj int pv[2], pid, ready, readfrom, cc; 916454Swnj char buf[BUFSIZ], sig; 926454Swnj int one = 1; 936454Swnj 946454Swnj (void) signal(SIGINT, SIG_DFL); 956454Swnj (void) signal(SIGQUIT, SIG_DFL); 966454Swnj (void) signal(SIGTERM, SIG_DFL); 9710883Ssam #ifdef DEBUG 986454Swnj { int t = open("/dev/tty", 2); 996454Swnj if (t >= 0) { 1006454Swnj ioctl(t, TIOCNOTTY, (char *)0); 1016454Swnj (void) close(t); 1026454Swnj } 1036454Swnj } 1046454Swnj #endif 1056454Swnj fromp->sin_port = ntohs((u_short)fromp->sin_port); 1066454Swnj if (fromp->sin_family != AF_INET || 10710596Ssam fromp->sin_port >= IPPORT_RESERVED) { 10817187Sralph syslog(LOG_ERR, "malformed from address\n"); 1096454Swnj exit(1); 11010596Ssam } 1116454Swnj (void) alarm(60); 1126454Swnj port = 0; 1136454Swnj for (;;) { 1146454Swnj char c; 11510596Ssam if (read(f, &c, 1) != 1) { 11617187Sralph syslog(LOG_ERR, "read: %m"); 11711238Ssam shutdown(f, 1+1); 1186454Swnj exit(1); 11910596Ssam } 1206454Swnj if (c == 0) 1216454Swnj break; 1226454Swnj port = port * 10 + c - '0'; 1236454Swnj } 1246454Swnj (void) alarm(0); 1256454Swnj if (port != 0) { 12627901Slepreau int lport = IPPORT_RESERVED - 1; 12710273Ssam s = rresvport(&lport); 12810596Ssam if (s < 0) { 12917187Sralph syslog(LOG_ERR, "can't get stderr port: %m"); 1306454Swnj exit(1); 13110596Ssam } 13210596Ssam if (port >= IPPORT_RESERVED) { 13317187Sralph syslog(LOG_ERR, "2nd port not reserved\n"); 13410596Ssam exit(1); 13510596Ssam } 1369243Ssam fromp->sin_port = htons((u_short)port); 13727901Slepreau if (connect(s, fromp, sizeof (*fromp)) < 0) { 13825985Skarels syslog(LOG_INFO, "connect second port: %m"); 1396454Swnj exit(1); 14010596Ssam } 1416454Swnj } 14210596Ssam dup2(f, 0); 14310596Ssam dup2(f, 1); 14410596Ssam dup2(f, 2); 14527901Slepreau hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr), 1468380Ssam fromp->sin_family); 14725985Skarels if (hp) 14825985Skarels hostname = hp->h_name; 14925985Skarels else 15025985Skarels hostname = inet_ntoa(fromp->sin_addr); 1516454Swnj getstr(remuser, sizeof(remuser), "remuser"); 1526454Swnj getstr(locuser, sizeof(locuser), "locuser"); 1536454Swnj getstr(cmdbuf, sizeof(cmdbuf), "command"); 1546454Swnj setpwent(); 1556454Swnj pwd = getpwnam(locuser); 1566454Swnj if (pwd == NULL) { 1576454Swnj error("Login incorrect.\n"); 1586454Swnj exit(1); 1596454Swnj } 1606454Swnj endpwent(); 1616454Swnj if (chdir(pwd->pw_dir) < 0) { 16227901Slepreau (void) chdir("/"); 16316370Skarels #ifdef notdef 1646454Swnj error("No remote directory.\n"); 1656454Swnj exit(1); 16616370Skarels #endif 1676454Swnj } 16824447Sbloom if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && 16925985Skarels ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) { 1706454Swnj error("Permission denied.\n"); 1716454Swnj exit(1); 1726454Swnj } 1736454Swnj (void) write(2, "\0", 1); 1746454Swnj if (port) { 1756454Swnj if (pipe(pv) < 0) { 1766454Swnj error("Can't make pipe.\n"); 1776454Swnj exit(1); 1786454Swnj } 1796454Swnj pid = fork(); 1806454Swnj if (pid == -1) { 1816454Swnj error("Try again.\n"); 1826454Swnj exit(1); 1836454Swnj } 1846454Swnj if (pid) { 1856454Swnj (void) close(0); (void) close(1); (void) close(2); 1866454Swnj (void) close(f); (void) close(pv[1]); 1876454Swnj readfrom = (1<<s) | (1<<pv[0]); 188*30265Smckusick ioctl(pv[0], FIONBIO, (char *)&one); 1896454Swnj /* should set s nbio! */ 1906454Swnj do { 1916454Swnj ready = readfrom; 19227901Slepreau if (select(16, &ready, (fd_set *)0, 19327901Slepreau (fd_set *)0, (struct timeval *)0) < 0) 1949212Ssam break; 1956454Swnj if (ready & (1<<s)) { 1966454Swnj if (read(s, &sig, 1) <= 0) 1976454Swnj readfrom &= ~(1<<s); 1986454Swnj else 1996454Swnj killpg(pid, sig); 2006454Swnj } 2016454Swnj if (ready & (1<<pv[0])) { 20211238Ssam errno = 0; 2036454Swnj cc = read(pv[0], buf, sizeof (buf)); 2046454Swnj if (cc <= 0) { 20510194Ssam shutdown(s, 1+1); 2066454Swnj readfrom &= ~(1<<pv[0]); 2076454Swnj } else 2086454Swnj (void) write(s, buf, cc); 2096454Swnj } 2106454Swnj } while (readfrom); 2116454Swnj exit(0); 2126454Swnj } 2136454Swnj setpgrp(0, getpid()); 2146454Swnj (void) close(s); (void) close(pv[0]); 2156454Swnj dup2(pv[1], 2); 2166454Swnj } 2176454Swnj if (*pwd->pw_shell == '\0') 2186454Swnj pwd->pw_shell = "/bin/sh"; 2196454Swnj (void) close(f); 22027901Slepreau (void) setgid((gid_t)pwd->pw_gid); 2219212Ssam initgroups(pwd->pw_name, pwd->pw_gid); 22227901Slepreau (void) setuid((uid_t)pwd->pw_uid); 2236454Swnj environ = envinit; 2246454Swnj strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); 2256454Swnj strncat(shell, pwd->pw_shell, sizeof(shell)-7); 2266454Swnj strncat(username, pwd->pw_name, sizeof(username)-6); 2276454Swnj cp = rindex(pwd->pw_shell, '/'); 2286454Swnj if (cp) 2296454Swnj cp++; 2306454Swnj else 2316454Swnj cp = pwd->pw_shell; 2326454Swnj execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); 2336454Swnj perror(pwd->pw_shell); 2346454Swnj exit(1); 2356454Swnj } 2366454Swnj 23727901Slepreau /*VARARGS1*/ 23825663Smckusick error(fmt, a1, a2, a3) 2396454Swnj char *fmt; 24025663Smckusick int a1, a2, a3; 2416454Swnj { 2426454Swnj char buf[BUFSIZ]; 2436454Swnj 2446454Swnj buf[0] = 1; 24525663Smckusick (void) sprintf(buf+1, fmt, a1, a2, a3); 2466454Swnj (void) write(2, buf, strlen(buf)); 2476454Swnj } 2486454Swnj 2496454Swnj getstr(buf, cnt, err) 2506454Swnj char *buf; 2516454Swnj int cnt; 2526454Swnj char *err; 2536454Swnj { 2546454Swnj char c; 2556454Swnj 2566454Swnj do { 2576454Swnj if (read(0, &c, 1) != 1) 2586454Swnj exit(1); 2596454Swnj *buf++ = c; 2606454Swnj if (--cnt == 0) { 2616454Swnj error("%s too long\n", err); 2626454Swnj exit(1); 2636454Swnj } 2646454Swnj } while (c != 0); 2656454Swnj } 266