16454Swnj #ifndef lint 2*10596Ssam static char sccsid[] = "@(#)rshd.c 4.11 83/01/22"; 36454Swnj #endif 46454Swnj 56454Swnj #include <sys/ioctl.h> 66454Swnj #include <sys/param.h> 76454Swnj #include <sys/socket.h> 89212Ssam 99212Ssam #include <netinet/in.h> 109212Ssam 119212Ssam #include <stdio.h> 126454Swnj #include <errno.h> 136454Swnj #include <pwd.h> 146454Swnj #include <wait.h> 156454Swnj #include <signal.h> 168380Ssam #include <netdb.h> 176454Swnj 186454Swnj int errno; 1910416Ssam int reapchild(); 208380Ssam struct sockaddr_in sin = { AF_INET }; 216454Swnj struct passwd *getpwnam(); 228380Ssam char *index(), *rindex(), *sprintf(); 2310273Ssam int options; 246454Swnj /* VARARGS 1 */ 256454Swnj int error(); 266454Swnj /* 276454Swnj * remote execute server: 286454Swnj * remuser\0 296454Swnj * locuser\0 306454Swnj * command\0 316454Swnj * data 326454Swnj */ 336454Swnj main(argc, argv) 346454Swnj int argc; 356454Swnj char **argv; 366454Swnj { 376454Swnj int f; 386454Swnj struct sockaddr_in from; 398380Ssam struct servent *sp; 406454Swnj 418380Ssam sp = getservbyname("shell", "tcp"); 428380Ssam if (sp == 0) { 438380Ssam fprintf(stderr, "rshd: tcp/shell: unknown service\n"); 448380Ssam exit(1); 458380Ssam } 466454Swnj #ifndef DEBUG 476454Swnj if (fork()) 486454Swnj exit(0); 496454Swnj for (f = 0; f < 10; f++) 506454Swnj (void) close(f); 516454Swnj (void) open("/", 0); 526454Swnj (void) dup2(0, 1); 536454Swnj (void) dup2(0, 2); 546454Swnj { int t = open("/dev/tty", 2); 556454Swnj if (t >= 0) { 566454Swnj ioctl(t, TIOCNOTTY, (char *)0); 576454Swnj (void) close(t); 586454Swnj } 596454Swnj } 606454Swnj #endif 619967Ssam sin.sin_port = sp->s_port; 626454Swnj argc--, argv++; 639212Ssam if (argc > 0 && !strcmp(argv[0], "-d")) { 6410273Ssam options |= SO_DEBUG; 6510273Ssam argc--, argv++; 6610273Ssam } 6710273Ssam if (argc > 0) { 688380Ssam int port = atoi(argv[0]); 698380Ssam 708380Ssam if (port < 0) { 718380Ssam fprintf(stderr, "%s: bad port #\n", argv[0]); 728380Ssam exit(1); 738380Ssam } 749967Ssam sin.sin_port = htons((u_short)port); 758380Ssam argc--, argv++; 768380Ssam } 779260Ssam f = socket(AF_INET, SOCK_STREAM, 0, 0); 789212Ssam if (f < 0) { 799212Ssam perror("rshd: socket"); 809212Ssam exit(1); 819212Ssam } 8210273Ssam if (options & SO_DEBUG && setsockopt(f, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 8310273Ssam perror("rshd: setsockopt (SO_DEBUG)"); 8410273Ssam #ifdef notdef 8510273Ssam if (setsockopt(f, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0) 8610273Ssam perror("rshd: setsockopt (SO_KEEPALIVE)"); 8710273Ssam #endif 889212Ssam if (bind(f, (caddr_t)&sin, sizeof (sin), 0) < 0) { 899212Ssam perror("rshd: bind"); 909212Ssam exit(1); 919212Ssam } 9210586Ssam sigset(SIGCHLD, reapchild); 939212Ssam listen(f, 10); 946454Swnj for (;;) { 959212Ssam int g, len = sizeof (from); 969212Ssam 979212Ssam g = accept(f, &from, &len, 0); 989212Ssam if (g < 0) { 9910416Ssam if (errno == EINTR) 10010416Ssam continue; 10110273Ssam perror("rshd: accept"); 1026454Swnj continue; 1036454Swnj } 1049212Ssam if (fork() == 0) { 1059212Ssam close(f); 1069212Ssam doit(g, &from); 1079212Ssam } 1089212Ssam close(g); 1096454Swnj } 1106454Swnj } 1116454Swnj 11210416Ssam reapchild() 11310416Ssam { 11410416Ssam union wait status; 11510416Ssam 11610416Ssam while (wait3(&status, WNOHANG, 0) > 0) 11710416Ssam ; 11810416Ssam } 11910416Ssam 1206454Swnj char username[20] = "USER="; 1216454Swnj char homedir[64] = "HOME="; 1226454Swnj char shell[64] = "SHELL="; 1236454Swnj char *envinit[] = 1246454Swnj {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", username, 0}; 1256454Swnj char **environ; 1266454Swnj 1276454Swnj doit(f, fromp) 1286454Swnj int f; 1296454Swnj struct sockaddr_in *fromp; 1306454Swnj { 1316454Swnj char cmdbuf[NCARGS+1], *cp; 1326454Swnj char locuser[16], remuser[16]; 1336454Swnj struct passwd *pwd; 134*10596Ssam int s, backoff; 1358380Ssam struct hostent *hp; 1366454Swnj short port; 1376454Swnj int pv[2], pid, ready, readfrom, cc; 1386454Swnj char buf[BUFSIZ], sig; 1396454Swnj int one = 1; 1406454Swnj 1416454Swnj (void) signal(SIGINT, SIG_DFL); 1426454Swnj (void) signal(SIGQUIT, SIG_DFL); 1436454Swnj (void) signal(SIGTERM, SIG_DFL); 14410273Ssam #ifndef DEBUG 1456454Swnj { int t = open("/dev/tty", 2); 1466454Swnj if (t >= 0) { 1476454Swnj ioctl(t, TIOCNOTTY, (char *)0); 1486454Swnj (void) close(t); 1496454Swnj } 1506454Swnj } 1516454Swnj #endif 1526454Swnj fromp->sin_port = ntohs((u_short)fromp->sin_port); 1536454Swnj if (fromp->sin_family != AF_INET || 154*10596Ssam fromp->sin_port >= IPPORT_RESERVED) { 155*10596Ssam fprintf(stderr, "rshd: malformed from address\n"); 1566454Swnj exit(1); 157*10596Ssam } 1586454Swnj (void) alarm(60); 1596454Swnj port = 0; 1606454Swnj for (;;) { 1616454Swnj char c; 162*10596Ssam if (read(f, &c, 1) != 1) { 163*10596Ssam int how = 1+1; 164*10596Ssam 165*10596Ssam perror("rshd: read"); 166*10596Ssam shutdown(f, &how); 1676454Swnj exit(1); 168*10596Ssam } 1696454Swnj if (c == 0) 1706454Swnj break; 1716454Swnj port = port * 10 + c - '0'; 1726454Swnj } 1736454Swnj (void) alarm(0); 1746454Swnj if (port != 0) { 175*10596Ssam int lport = IPPORT_RESERVED - 1, retryshift; 17610273Ssam s = rresvport(&lport); 177*10596Ssam if (s < 0) { 178*10596Ssam perror("rshd: can't get stderr port"); 1796454Swnj exit(1); 180*10596Ssam } 181*10596Ssam if (port >= IPPORT_RESERVED) { 182*10596Ssam fprintf(stderr, "rshd: 2nd port not reserved\n"); 183*10596Ssam exit(1); 184*10596Ssam } 1859243Ssam fromp->sin_port = htons((u_short)port); 186*10596Ssam for (backoff = 1; backoff != 0; backoff <<= 1) { 187*10596Ssam (void) alarm(60); 188*10596Ssam if (connect(s, fromp, sizeof (*fromp), 0) >= 0) 189*10596Ssam break; 190*10596Ssam (void) alarm(0); 191*10596Ssam sleep(backoff); 192*10596Ssam } 193*10596Ssam if (backoff == 0) { 194*10596Ssam perror("rshd: connect"); 1956454Swnj exit(1); 196*10596Ssam } 1976454Swnj } 198*10596Ssam dup2(f, 0); 199*10596Ssam dup2(f, 1); 200*10596Ssam dup2(f, 2); 2018380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 2028380Ssam fromp->sin_family); 2038380Ssam if (hp == 0) { 2046454Swnj error("Host name for your address unknown\n"); 2056454Swnj exit(1); 2066454Swnj } 2076454Swnj getstr(remuser, sizeof(remuser), "remuser"); 2086454Swnj getstr(locuser, sizeof(locuser), "locuser"); 2096454Swnj getstr(cmdbuf, sizeof(cmdbuf), "command"); 2106454Swnj setpwent(); 2116454Swnj pwd = getpwnam(locuser); 2126454Swnj if (pwd == NULL) { 2136454Swnj error("Login incorrect.\n"); 2146454Swnj exit(1); 2156454Swnj } 2166454Swnj endpwent(); 2176454Swnj if (chdir(pwd->pw_dir) < 0) { 2186454Swnj error("No remote directory.\n"); 2196454Swnj exit(1); 2206454Swnj } 2218380Ssam if (ruserok(hp->h_name, remuser, locuser) < 0) { 2226454Swnj error("Permission denied.\n"); 2236454Swnj exit(1); 2246454Swnj } 2256454Swnj (void) write(2, "\0", 1); 2266454Swnj if (port) { 2276454Swnj if (pipe(pv) < 0) { 2286454Swnj error("Can't make pipe.\n"); 2296454Swnj exit(1); 2306454Swnj } 2316454Swnj pid = fork(); 2326454Swnj if (pid == -1) { 2336454Swnj error("Try again.\n"); 2346454Swnj exit(1); 2356454Swnj } 2366454Swnj if (pid) { 2376454Swnj (void) close(0); (void) close(1); (void) close(2); 2386454Swnj (void) close(f); (void) close(pv[1]); 2396454Swnj readfrom = (1<<s) | (1<<pv[0]); 2406454Swnj ioctl(pv[1], FIONBIO, (char *)&one); 2416454Swnj /* should set s nbio! */ 2426454Swnj do { 2436454Swnj ready = readfrom; 2449212Ssam if (select(16, &ready, 0, 0, 0) < 0) 2459212Ssam break; 2466454Swnj if (ready & (1<<s)) { 2476454Swnj if (read(s, &sig, 1) <= 0) 2486454Swnj readfrom &= ~(1<<s); 2496454Swnj else 2506454Swnj killpg(pid, sig); 2516454Swnj } 2526454Swnj if (ready & (1<<pv[0])) { 2536454Swnj cc = read(pv[0], buf, sizeof (buf)); 2546454Swnj if (cc <= 0) { 25510194Ssam shutdown(s, 1+1); 2566454Swnj readfrom &= ~(1<<pv[0]); 2576454Swnj } else 2586454Swnj (void) write(s, buf, cc); 2596454Swnj } 2606454Swnj } while (readfrom); 2616454Swnj exit(0); 2626454Swnj } 2636454Swnj setpgrp(0, getpid()); 2646454Swnj (void) close(s); (void) close(pv[0]); 2656454Swnj dup2(pv[1], 2); 2666454Swnj } 2676454Swnj if (*pwd->pw_shell == '\0') 2686454Swnj pwd->pw_shell = "/bin/sh"; 2696454Swnj (void) close(f); 2709212Ssam initgroups(pwd->pw_name, pwd->pw_gid); 2716454Swnj (void) setuid(pwd->pw_uid); 2726454Swnj (void) setgid(pwd->pw_gid); 2736454Swnj environ = envinit; 2746454Swnj strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); 2756454Swnj strncat(shell, pwd->pw_shell, sizeof(shell)-7); 2766454Swnj strncat(username, pwd->pw_name, sizeof(username)-6); 2776454Swnj cp = rindex(pwd->pw_shell, '/'); 2786454Swnj if (cp) 2796454Swnj cp++; 2806454Swnj else 2816454Swnj cp = pwd->pw_shell; 2826454Swnj execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); 2836454Swnj perror(pwd->pw_shell); 2846454Swnj exit(1); 2856454Swnj protofail: 2866454Swnj error("rsh: protocol failure detected by remote\n"); 2876454Swnj exit(1); 2886454Swnj } 2896454Swnj 2906454Swnj /* VARARGS 1 */ 2916454Swnj error(fmt) 2926454Swnj char *fmt; 2936454Swnj { 2946454Swnj char buf[BUFSIZ]; 2956454Swnj 2966454Swnj buf[0] = 1; 2976454Swnj (void) sprintf(buf+1, fmt); 2986454Swnj (void) write(2, buf, strlen(buf)); 2996454Swnj } 3006454Swnj 3016454Swnj getstr(buf, cnt, err) 3026454Swnj char *buf; 3036454Swnj int cnt; 3046454Swnj char *err; 3056454Swnj { 3066454Swnj char c; 3076454Swnj 3086454Swnj do { 3096454Swnj if (read(0, &c, 1) != 1) 3106454Swnj exit(1); 3116454Swnj *buf++ = c; 3126454Swnj if (--cnt == 0) { 3136454Swnj error("%s too long\n", err); 3146454Swnj exit(1); 3156454Swnj } 3166454Swnj } while (c != 0); 3176454Swnj } 318