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