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