1 1.39 mrg /* $NetBSD: rsh.c,v 1.39 2021/04/13 06:25:49 mrg Exp $ */ 2 1.4 tls 3 1.1 cgd /*- 4 1.5 mrg * Copyright (c) 1983, 1990, 1993, 1994 5 1.5 mrg * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.22 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.11 christos #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.30 lukem __COPYRIGHT("@(#) Copyright (c) 1983, 1990, 1993, 1994\ 35 1.30 lukem The Regents of the University of California. All rights reserved."); 36 1.1 cgd #endif /* not lint */ 37 1.1 cgd 38 1.1 cgd #ifndef lint 39 1.11 christos #if 0 40 1.11 christos static char sccsid[] = "@(#)rsh.c 8.4 (Berkeley) 4/29/95"; 41 1.11 christos #else 42 1.39 mrg __RCSID("$NetBSD: rsh.c,v 1.39 2021/04/13 06:25:49 mrg Exp $"); 43 1.11 christos #endif 44 1.1 cgd #endif /* not lint */ 45 1.1 cgd 46 1.1 cgd #include <sys/types.h> 47 1.1 cgd #include <sys/socket.h> 48 1.1 cgd #include <sys/ioctl.h> 49 1.1 cgd #include <sys/file.h> 50 1.7 mrg #include <poll.h> 51 1.1 cgd 52 1.1 cgd #include <netinet/in.h> 53 1.20 joff #include <netinet/tcp.h> 54 1.1 cgd #include <netdb.h> 55 1.1 cgd 56 1.5 mrg #include <err.h> 57 1.5 mrg #include <errno.h> 58 1.23 christos #include <limits.h> 59 1.1 cgd #include <pwd.h> 60 1.3 jtc #include <signal.h> 61 1.15 wiz #include <stdarg.h> 62 1.1 cgd #include <stdio.h> 63 1.5 mrg #include <stdlib.h> 64 1.1 cgd #include <string.h> 65 1.5 mrg #include <unistd.h> 66 1.5 mrg 67 1.1 cgd #include "pathnames.h" 68 1.23 christos #include "getport.h" 69 1.1 cgd 70 1.1 cgd 71 1.1 cgd /* 72 1.1 cgd * rsh - remote shell 73 1.1 cgd */ 74 1.10 christos int remerr; 75 1.10 christos 76 1.10 christos static int sigs[] = { SIGINT, SIGTERM, SIGQUIT }; 77 1.1 cgd 78 1.33 joerg static char *copyargs(char **); 79 1.33 joerg static void sendsig(int); 80 1.33 joerg static int checkfd(struct pollfd *, int); 81 1.33 joerg static void talk(int, sigset_t *, pid_t, int); 82 1.33 joerg __dead static void usage(void); 83 1.12 christos #ifdef IN_RCMD 84 1.15 wiz int orcmd(char **, int, const char *, 85 1.15 wiz const char *, const char *, int *); 86 1.15 wiz int orcmd_af(char **, int, const char *, 87 1.15 wiz const char *, const char *, int *, int); 88 1.38 enami static int relay_signal; 89 1.12 christos #endif 90 1.5 mrg 91 1.5 mrg int 92 1.15 wiz main(int argc, char **argv) 93 1.1 cgd { 94 1.1 cgd struct passwd *pw; 95 1.1 cgd struct servent *sp; 96 1.10 christos sigset_t oset, nset; 97 1.20 joff struct protoent *proto; 98 1.10 christos 99 1.7 mrg #ifdef IN_RCMD 100 1.38 enami char *locuser = 0, *loop, *relay; 101 1.7 mrg #endif /* IN_RCMD */ 102 1.31 lukem int argoff, asrsh, ch, dflag, nflag, one, rem; 103 1.31 lukem size_t i; 104 1.26 ginsbach int family = AF_UNSPEC; 105 1.5 mrg pid_t pid; 106 1.5 mrg uid_t uid; 107 1.9 mrg char *args, *host, *p, *user, *name; 108 1.1 cgd 109 1.1 cgd argoff = asrsh = dflag = nflag = 0; 110 1.1 cgd one = 1; 111 1.1 cgd host = user = NULL; 112 1.17 hubertf sp = NULL; 113 1.1 cgd 114 1.8 mrg #ifndef IN_RCMD 115 1.7 mrg /* 116 1.8 mrg * If called as something other than "rsh" use it as the host name, 117 1.8 mrg * only for rsh. 118 1.7 mrg */ 119 1.14 cgd if (strcmp(getprogname(), "rsh") == 0) 120 1.7 mrg asrsh = 1; 121 1.14 cgd else { 122 1.14 cgd host = strdup(getprogname()); 123 1.14 cgd if (host == NULL) 124 1.14 cgd err(1, NULL); 125 1.14 cgd } 126 1.8 mrg #endif /* IN_RCMD */ 127 1.1 cgd 128 1.1 cgd /* handle "rsh host flags" */ 129 1.1 cgd if (!host && argc > 2 && argv[1][0] != '-') { 130 1.1 cgd host = argv[1]; 131 1.1 cgd argoff = 1; 132 1.1 cgd } 133 1.1 cgd 134 1.7 mrg #ifdef IN_RCMD 135 1.38 enami if ((relay = getenv("RCMD_RELAY_SIGNAL")) && strcmp(relay, "YES") == 0) 136 1.38 enami relay_signal = 1; 137 1.7 mrg if ((loop = getenv("RCMD_LOOP")) && strcmp(loop, "YES") == 0) 138 1.7 mrg warnx("rcmd appears to be looping!"); 139 1.7 mrg 140 1.32 gson setenv("RCMD_LOOP", "YES", 1); 141 1.7 mrg 142 1.26 ginsbach # define OPTIONS "468KLdel:np:u:w" 143 1.7 mrg 144 1.7 mrg #else /* IN_RCMD */ 145 1.7 mrg 146 1.26 ginsbach # define OPTIONS "468KLdel:np:w" 147 1.7 mrg 148 1.7 mrg #endif /* IN_RCMD */ 149 1.7 mrg 150 1.7 mrg if (!(pw = getpwuid(uid = getuid()))) 151 1.7 mrg errx(1, "unknown user id"); 152 1.7 mrg 153 1.9 mrg if ((name = strdup(pw->pw_name)) == NULL) 154 1.9 mrg err(1, "malloc"); 155 1.10 christos while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1) 156 1.38 enami switch (ch) { 157 1.26 ginsbach case '4': 158 1.26 ginsbach family = AF_INET; 159 1.26 ginsbach break; 160 1.26 ginsbach case '6': 161 1.26 ginsbach family = AF_INET6; 162 1.26 ginsbach break; 163 1.1 cgd case 'K': 164 1.1 cgd break; 165 1.1 cgd case 'L': /* -8Lew are ignored to allow rlogin aliases */ 166 1.1 cgd case 'e': 167 1.1 cgd case 'w': 168 1.1 cgd case '8': 169 1.1 cgd break; 170 1.1 cgd case 'd': 171 1.1 cgd dflag = 1; 172 1.1 cgd break; 173 1.1 cgd case 'l': 174 1.1 cgd user = optarg; 175 1.1 cgd break; 176 1.1 cgd case 'n': 177 1.1 cgd nflag = 1; 178 1.1 cgd break; 179 1.17 hubertf case 'p': 180 1.23 christos sp = getport(optarg, "tcp"); 181 1.17 hubertf break; 182 1.7 mrg #ifdef IN_RCMD 183 1.7 mrg case 'u': 184 1.9 mrg if (getuid() != 0 && optarg && name && 185 1.9 mrg strcmp(name, optarg) != 0) 186 1.7 mrg errx(1,"only super user can use the -u option"); 187 1.7 mrg locuser = optarg; 188 1.7 mrg break; 189 1.7 mrg #endif /* IN_RCMD */ 190 1.1 cgd case '?': 191 1.1 cgd default: 192 1.1 cgd usage(); 193 1.1 cgd } 194 1.1 cgd optind += argoff; 195 1.1 cgd 196 1.1 cgd /* if haven't gotten a host yet, do so */ 197 1.1 cgd if (!host && !(host = argv[optind++])) 198 1.1 cgd usage(); 199 1.1 cgd 200 1.1 cgd /* if no further arguments, must have been called as rlogin. */ 201 1.1 cgd if (!argv[optind]) { 202 1.7 mrg #ifdef IN_RCMD 203 1.7 mrg usage(); 204 1.7 mrg #else 205 1.1 cgd if (asrsh) 206 1.23 christos *argv = __UNCONST("rlogin"); 207 1.37 dholland setuid(uid); 208 1.1 cgd execv(_PATH_RLOGIN, argv); 209 1.5 mrg err(1, "can't exec %s", _PATH_RLOGIN); 210 1.7 mrg #endif 211 1.1 cgd } 212 1.1 cgd 213 1.1 cgd argc -= optind; 214 1.1 cgd argv += optind; 215 1.1 cgd 216 1.5 mrg /* Accept user1@host format, though "-l user2" overrides user1 */ 217 1.5 mrg p = strchr(host, '@'); 218 1.5 mrg if (p) { 219 1.5 mrg *p = '\0'; 220 1.5 mrg if (!user && p > host) 221 1.5 mrg user = host; 222 1.5 mrg host = p + 1; 223 1.5 mrg if (*host == '\0') 224 1.5 mrg usage(); 225 1.1 cgd } 226 1.1 cgd if (!user) 227 1.9 mrg user = name; 228 1.1 cgd 229 1.1 cgd 230 1.1 cgd args = copyargs(argv); 231 1.1 cgd 232 1.1 cgd if (sp == NULL) 233 1.1 cgd sp = getservbyname("shell", "tcp"); 234 1.5 mrg if (sp == NULL) 235 1.5 mrg errx(1, "shell/tcp: unknown service"); 236 1.1 cgd 237 1.7 mrg 238 1.7 mrg #ifdef IN_RCMD 239 1.13 itojun rem = orcmd_af(&host, sp->s_port, locuser ? locuser : 240 1.1 cgd #else 241 1.13 itojun rem = rcmd_af(&host, sp->s_port, 242 1.1 cgd #endif 243 1.26 ginsbach name, user, args, &remerr, family); 244 1.9 mrg (void)free(name); 245 1.1 cgd 246 1.1 cgd if (rem < 0) 247 1.1 cgd exit(1); 248 1.1 cgd 249 1.10 christos if (remerr < 0) 250 1.5 mrg errx(1, "can't establish stderr"); 251 1.1 cgd if (dflag) { 252 1.1 cgd if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, 253 1.1 cgd sizeof(one)) < 0) 254 1.7 mrg warn("setsockopt remote"); 255 1.10 christos if (setsockopt(remerr, SOL_SOCKET, SO_DEBUG, &one, 256 1.1 cgd sizeof(one)) < 0) 257 1.7 mrg warn("setsockopt stderr"); 258 1.1 cgd } 259 1.20 joff proto = getprotobyname("tcp"); 260 1.20 joff setsockopt(rem, proto->p_proto, TCP_NODELAY, &one, sizeof(one)); 261 1.20 joff setsockopt(remerr, proto->p_proto, TCP_NODELAY, &one, sizeof(one)); 262 1.20 joff 263 1.1 cgd 264 1.25 ginsbach (void)setuid(uid); 265 1.10 christos 266 1.25 ginsbach (void)sigemptyset(&nset); 267 1.10 christos for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++) 268 1.25 ginsbach (void)sigaddset(&nset, sigs[i]); 269 1.10 christos 270 1.25 ginsbach (void)sigprocmask(SIG_BLOCK, &nset, &oset); 271 1.10 christos 272 1.38 enami #ifdef IN_RCMD 273 1.38 enami if (!relay_signal) 274 1.38 enami #endif 275 1.38 enami for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++) { 276 1.38 enami struct sigaction sa; 277 1.10 christos 278 1.38 enami if (sa.sa_handler != SIG_IGN) { 279 1.38 enami sa.sa_handler = sendsig; 280 1.38 enami (void)sigaction(sigs[i], &sa, NULL); 281 1.38 enami } 282 1.10 christos } 283 1.1 cgd 284 1.1 cgd if (!nflag) { 285 1.1 cgd pid = fork(); 286 1.5 mrg if (pid < 0) 287 1.5 mrg err(1, "fork"); 288 1.1 cgd } 289 1.10 christos else 290 1.10 christos pid = -1; 291 1.1 cgd 292 1.34 enami (void)ioctl(remerr, FIONBIO, &one); 293 1.34 enami (void)ioctl(rem, FIONBIO, &one); 294 1.1 cgd 295 1.10 christos talk(nflag, &oset, pid, rem); 296 1.1 cgd 297 1.1 cgd if (!nflag) 298 1.1 cgd (void)kill(pid, SIGKILL); 299 1.1 cgd exit(0); 300 1.1 cgd } 301 1.1 cgd 302 1.33 joerg static int 303 1.15 wiz checkfd(struct pollfd *fdp, int outfd) 304 1.10 christos { 305 1.10 christos int nr, nw; 306 1.10 christos char buf[BUFSIZ]; 307 1.10 christos 308 1.10 christos if (fdp->revents & (POLLNVAL|POLLERR|POLLHUP)) 309 1.10 christos return -1; 310 1.35 enami 311 1.10 christos if ((fdp->revents & POLLIN) == 0) 312 1.10 christos return 0; 313 1.10 christos 314 1.10 christos errno = 0; 315 1.34 enami nr = read(fdp->fd, buf, sizeof buf); 316 1.10 christos 317 1.10 christos if (nr <= 0) { 318 1.10 christos if (errno != EAGAIN) 319 1.10 christos return -1; 320 1.10 christos else 321 1.10 christos return 0; 322 1.10 christos } 323 1.10 christos else { 324 1.10 christos char *bc = buf; 325 1.10 christos while (nr) { 326 1.10 christos if ((nw = write(outfd, bc, nr)) <= 0) 327 1.10 christos return -1; 328 1.10 christos nr -= nw; 329 1.10 christos bc += nw; 330 1.10 christos } 331 1.10 christos return 0; 332 1.10 christos } 333 1.10 christos } 334 1.10 christos 335 1.33 joerg static void 336 1.15 wiz talk(int nflag, sigset_t *oset, __pid_t pid, int rem) 337 1.1 cgd { 338 1.10 christos int nr, nw, nfds; 339 1.36 enami struct pollfd fds[3], *fdp = &fds[0]; 340 1.5 mrg char *bp, buf[BUFSIZ]; 341 1.1 cgd 342 1.1 cgd if (!nflag && pid == 0) { 343 1.10 christos (void)close(remerr); 344 1.1 cgd 345 1.10 christos fdp->events = POLLOUT|POLLNVAL|POLLERR|POLLHUP; 346 1.10 christos fdp->fd = rem; 347 1.10 christos nr = 0; 348 1.1 cgd bp = buf; 349 1.1 cgd 350 1.10 christos for (;;) { 351 1.10 christos errno = 0; 352 1.10 christos 353 1.10 christos if (nr == 0) { 354 1.10 christos if ((nr = read(0, buf, sizeof buf)) == 0) 355 1.10 christos goto done; 356 1.10 christos if (nr == -1) { 357 1.10 christos if (errno == EIO) 358 1.10 christos goto done; 359 1.28 ginsbach if (errno == EINTR) { 360 1.28 ginsbach nr = 0; 361 1.10 christos continue; 362 1.28 ginsbach } 363 1.10 christos err(1, "read"); 364 1.10 christos } 365 1.10 christos bp = buf; 366 1.10 christos } 367 1.10 christos 368 1.10 christos rewrite: if (poll(fdp, 1, INFTIM) == -1) { 369 1.10 christos if (errno != EINTR) 370 1.10 christos err(1, "poll"); 371 1.10 christos goto rewrite; 372 1.10 christos } 373 1.10 christos 374 1.10 christos if (fdp->revents & (POLLNVAL|POLLERR|POLLHUP)) 375 1.7 mrg err(1, "poll"); 376 1.10 christos 377 1.10 christos if ((fdp->revents & POLLOUT) == 0) 378 1.10 christos goto rewrite; 379 1.10 christos 380 1.34 enami nw = write(rem, bp, nr); 381 1.10 christos 382 1.10 christos if (nw < 0) { 383 1.10 christos if (errno == EAGAIN) 384 1.10 christos continue; 385 1.10 christos err(1, "write"); 386 1.10 christos } 387 1.10 christos bp += nw; 388 1.10 christos nr -= nw; 389 1.1 cgd } 390 1.1 cgd done: 391 1.1 cgd (void)shutdown(rem, 1); 392 1.1 cgd exit(0); 393 1.1 cgd } 394 1.1 cgd 395 1.36 enami fdp = &fds[1]; 396 1.7 mrg nfds = 2; 397 1.36 enami fds[0].events = 0; 398 1.38 enami #ifdef IN_RCMD 399 1.38 enami if (relay_signal) { 400 1.38 enami fdp = &fds[0]; 401 1.38 enami nfds = 3; 402 1.38 enami fds[0].events = POLLIN|POLLNVAL|POLLERR|POLLHUP; 403 1.38 enami fds[0].fd = 2; 404 1.38 enami } else 405 1.36 enami #endif 406 1.38 enami (void)sigprocmask(SIG_SETMASK, oset, NULL); 407 1.36 enami fds[1].events = fds[2].events = POLLIN|POLLNVAL|POLLERR|POLLHUP; 408 1.36 enami fds[1].fd = remerr; 409 1.36 enami fds[2].fd = rem; 410 1.1 cgd do { 411 1.10 christos if (poll(fdp, nfds, INFTIM) == -1) { 412 1.5 mrg if (errno != EINTR) 413 1.7 mrg err(1, "poll"); 414 1.1 cgd continue; 415 1.1 cgd } 416 1.36 enami if ((fds[1].events != 0 && checkfd(&fds[1], 2) == -1) 417 1.36 enami #ifdef IN_RCMD 418 1.36 enami || (fds[0].events != 0 && checkfd(&fds[0], remerr) == -1) 419 1.36 enami #endif 420 1.36 enami ) { 421 1.36 enami nfds--; 422 1.36 enami fds[1].events = 0; 423 1.36 enami #ifdef IN_RCMD 424 1.38 enami if (relay_signal) { 425 1.38 enami nfds--; 426 1.38 enami fds[0].events = 0; 427 1.38 enami } 428 1.36 enami #endif 429 1.36 enami fdp = &fds[2]; 430 1.1 cgd } 431 1.36 enami if (fds[2].events != 0 && checkfd(&fds[2], 1) == -1) { 432 1.10 christos nfds--; 433 1.36 enami fds[2].events = 0; 434 1.1 cgd } 435 1.10 christos } 436 1.10 christos while (nfds); 437 1.1 cgd } 438 1.1 cgd 439 1.33 joerg static void 440 1.15 wiz sendsig(int sig) 441 1.5 mrg { 442 1.1 cgd char signo; 443 1.5 mrg 444 1.5 mrg signo = sig; 445 1.35 enami (void)write(remerr, &signo, 1); 446 1.1 cgd } 447 1.1 cgd 448 1.33 joerg static char * 449 1.15 wiz copyargs(char **argv) 450 1.1 cgd { 451 1.5 mrg int cc; 452 1.18 itojun char **ap, *args, *p, *ep; 453 1.1 cgd 454 1.1 cgd cc = 0; 455 1.1 cgd for (ap = argv; *ap; ++ap) 456 1.1 cgd cc += strlen(*ap) + 1; 457 1.39 mrg if (cc == 0) 458 1.39 mrg usage(); 459 1.5 mrg if (!(args = malloc((u_int)cc))) 460 1.10 christos err(1, "malloc"); 461 1.18 itojun ep = args + cc; 462 1.7 mrg for (p = args, *p = '\0', ap = argv; *ap; ++ap) { 463 1.18 itojun (void)strlcpy(p, *ap, ep - p); 464 1.7 mrg p += strlen(p); 465 1.1 cgd if (ap[1]) 466 1.1 cgd *p++ = ' '; 467 1.1 cgd } 468 1.7 mrg *p = '\0'; 469 1.5 mrg return (args); 470 1.1 cgd } 471 1.1 cgd 472 1.33 joerg static void 473 1.15 wiz usage(void) 474 1.1 cgd { 475 1.5 mrg 476 1.1 cgd (void)fprintf(stderr, 477 1.29 wiz "usage: %s [-46dn] [-l login] [-p port]%s [login@]host command\n", 478 1.29 wiz getprogname(), 479 1.7 mrg #ifdef IN_RCMD 480 1.29 wiz " [-u locuser]" 481 1.1 cgd #else 482 1.29 wiz "" 483 1.1 cgd #endif 484 1.7 mrg ); 485 1.1 cgd exit(1); 486 1.1 cgd } 487