1 #ifndef lint 2 static char sccsid[] = "@(#)rshd.c 4.15 83/05/03"; 3 #endif 4 5 #include <sys/ioctl.h> 6 #include <sys/param.h> 7 #include <sys/socket.h> 8 9 #include <netinet/in.h> 10 11 #include <stdio.h> 12 #include <errno.h> 13 #include <pwd.h> 14 #include <wait.h> 15 #include <signal.h> 16 #include <netdb.h> 17 18 int errno; 19 int reapchild(); 20 struct sockaddr_in sin = { AF_INET }; 21 struct passwd *getpwnam(); 22 char *index(), *rindex(), *sprintf(); 23 int options; 24 /* VARARGS 1 */ 25 int error(); 26 /* 27 * remote execute server: 28 * remuser\0 29 * locuser\0 30 * command\0 31 * data 32 */ 33 main(argc, argv) 34 int argc; 35 char **argv; 36 { 37 int f; 38 struct sockaddr_in from; 39 struct servent *sp; 40 41 sp = getservbyname("shell", "tcp"); 42 if (sp == 0) { 43 fprintf(stderr, "rshd: tcp/shell: unknown service\n"); 44 exit(1); 45 } 46 #ifndef DEBUG 47 if (fork()) 48 exit(0); 49 for (f = 0; f < 10; f++) 50 (void) close(f); 51 (void) open("/", 0); 52 (void) dup2(0, 1); 53 (void) dup2(0, 2); 54 { int t = open("/dev/tty", 2); 55 if (t >= 0) { 56 ioctl(t, TIOCNOTTY, (char *)0); 57 (void) close(t); 58 } 59 } 60 #endif 61 sin.sin_port = sp->s_port; 62 argc--, argv++; 63 if (argc > 0 && !strcmp(argv[0], "-d")) { 64 options |= SO_DEBUG; 65 argc--, argv++; 66 } 67 if (argc > 0) { 68 int port = atoi(argv[0]); 69 70 if (port < 0) { 71 fprintf(stderr, "%s: bad port #\n", argv[0]); 72 exit(1); 73 } 74 sin.sin_port = htons((u_short)port); 75 argc--, argv++; 76 } 77 f = socket(AF_INET, SOCK_STREAM, 0, 0); 78 if (f < 0) { 79 perror("rshd: socket"); 80 exit(1); 81 } 82 if (options & SO_DEBUG && setsockopt(f, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 83 perror("rshd: setsockopt (SO_DEBUG)"); 84 if (setsockopt(f, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0) 85 perror("rshd: setsockopt (SO_KEEPALIVE)"); 86 if (bind(f, (caddr_t)&sin, sizeof (sin), 0) < 0) { 87 perror("rshd: bind"); 88 exit(1); 89 } 90 sigset(SIGCHLD, reapchild); 91 listen(f, 10); 92 for (;;) { 93 int g, len = sizeof (from); 94 95 g = accept(f, &from, &len, 0); 96 if (g < 0) { 97 if (errno == EINTR) 98 continue; 99 perror("rshd: accept"); 100 continue; 101 } 102 if (fork() == 0) { 103 signal(SIGCHLD, SIG_IGN); 104 close(f); 105 doit(g, &from); 106 } 107 close(g); 108 } 109 } 110 111 reapchild() 112 { 113 union wait status; 114 115 while (wait3(&status, WNOHANG, 0) > 0) 116 ; 117 } 118 119 char username[20] = "USER="; 120 char homedir[64] = "HOME="; 121 char shell[64] = "SHELL="; 122 char *envinit[] = 123 {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", username, 0}; 124 char **environ; 125 126 doit(f, fromp) 127 int f; 128 struct sockaddr_in *fromp; 129 { 130 char cmdbuf[NCARGS+1], *cp; 131 char locuser[16], remuser[16]; 132 struct passwd *pwd; 133 int s, backoff; 134 struct hostent *hp; 135 short port; 136 int pv[2], pid, ready, readfrom, cc; 137 char buf[BUFSIZ], sig; 138 int one = 1; 139 140 (void) signal(SIGINT, SIG_DFL); 141 (void) signal(SIGQUIT, SIG_DFL); 142 (void) signal(SIGTERM, SIG_DFL); 143 #ifdef DEBUG 144 { int t = open("/dev/tty", 2); 145 if (t >= 0) { 146 ioctl(t, TIOCNOTTY, (char *)0); 147 (void) close(t); 148 } 149 } 150 #endif 151 fromp->sin_port = ntohs((u_short)fromp->sin_port); 152 if (fromp->sin_family != AF_INET || 153 fromp->sin_port >= IPPORT_RESERVED) { 154 fprintf(stderr, "rshd: malformed from address\n"); 155 exit(1); 156 } 157 (void) alarm(60); 158 port = 0; 159 for (;;) { 160 char c; 161 if (read(f, &c, 1) != 1) { 162 perror("rshd: read"); 163 shutdown(f, 1+1); 164 exit(1); 165 } 166 if (c == 0) 167 break; 168 port = port * 10 + c - '0'; 169 } 170 (void) alarm(0); 171 if (port != 0) { 172 int lport = IPPORT_RESERVED - 1, retryshift; 173 s = rresvport(&lport); 174 if (s < 0) { 175 perror("rshd: can't get stderr port"); 176 exit(1); 177 } 178 if (port >= IPPORT_RESERVED) { 179 fprintf(stderr, "rshd: 2nd port not reserved\n"); 180 exit(1); 181 } 182 fromp->sin_port = htons((u_short)port); 183 if (connect(s, fromp, sizeof (*fromp), 0) < 0) { 184 perror("rshd: connect"); 185 exit(1); 186 } 187 } 188 dup2(f, 0); 189 dup2(f, 1); 190 dup2(f, 2); 191 hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 192 fromp->sin_family); 193 if (hp == 0) { 194 error("Host name for your address unknown\n"); 195 exit(1); 196 } 197 getstr(remuser, sizeof(remuser), "remuser"); 198 getstr(locuser, sizeof(locuser), "locuser"); 199 getstr(cmdbuf, sizeof(cmdbuf), "command"); 200 setpwent(); 201 pwd = getpwnam(locuser); 202 if (pwd == NULL) { 203 error("Login incorrect.\n"); 204 exit(1); 205 } 206 endpwent(); 207 if (chdir(pwd->pw_dir) < 0) { 208 error("No remote directory.\n"); 209 exit(1); 210 } 211 if (ruserok(hp->h_name, pwd->pw_uid == 0, remuser, locuser) < 0) { 212 error("Permission denied.\n"); 213 exit(1); 214 } 215 (void) write(2, "\0", 1); 216 if (port) { 217 if (pipe(pv) < 0) { 218 error("Can't make pipe.\n"); 219 exit(1); 220 } 221 pid = fork(); 222 if (pid == -1) { 223 error("Try again.\n"); 224 exit(1); 225 } 226 if (pid) { 227 (void) close(0); (void) close(1); (void) close(2); 228 (void) close(f); (void) close(pv[1]); 229 readfrom = (1<<s) | (1<<pv[0]); 230 ioctl(pv[1], FIONBIO, (char *)&one); 231 /* should set s nbio! */ 232 do { 233 ready = readfrom; 234 if (select(16, &ready, 0, 0, 0) < 0) 235 break; 236 if (ready & (1<<s)) { 237 if (read(s, &sig, 1) <= 0) 238 readfrom &= ~(1<<s); 239 else 240 killpg(pid, sig); 241 } 242 if (ready & (1<<pv[0])) { 243 errno = 0; 244 cc = read(pv[0], buf, sizeof (buf)); 245 if (cc <= 0) { 246 shutdown(s, 1+1); 247 readfrom &= ~(1<<pv[0]); 248 } else 249 (void) write(s, buf, cc); 250 } 251 } while (readfrom); 252 exit(0); 253 } 254 setpgrp(0, getpid()); 255 (void) close(s); (void) close(pv[0]); 256 dup2(pv[1], 2); 257 } 258 if (*pwd->pw_shell == '\0') 259 pwd->pw_shell = "/bin/sh"; 260 (void) close(f); 261 initgroups(pwd->pw_name, pwd->pw_gid); 262 (void) setgid(pwd->pw_gid); 263 (void) setuid(pwd->pw_uid); 264 environ = envinit; 265 strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); 266 strncat(shell, pwd->pw_shell, sizeof(shell)-7); 267 strncat(username, pwd->pw_name, sizeof(username)-6); 268 cp = rindex(pwd->pw_shell, '/'); 269 if (cp) 270 cp++; 271 else 272 cp = pwd->pw_shell; 273 execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); 274 perror(pwd->pw_shell); 275 exit(1); 276 protofail: 277 error("rsh: protocol failure detected by remote\n"); 278 exit(1); 279 } 280 281 /* VARARGS 1 */ 282 error(fmt) 283 char *fmt; 284 { 285 char buf[BUFSIZ]; 286 287 buf[0] = 1; 288 (void) sprintf(buf+1, fmt); 289 (void) write(2, buf, strlen(buf)); 290 } 291 292 getstr(buf, cnt, err) 293 char *buf; 294 int cnt; 295 char *err; 296 { 297 char c; 298 299 do { 300 if (read(0, &c, 1) != 1) 301 exit(1); 302 *buf++ = c; 303 if (--cnt == 0) { 304 error("%s too long\n", err); 305 exit(1); 306 } 307 } while (c != 0); 308 } 309