Annotation of src/usr.bin/rsh/rsh.c, Revision 1.35
1.35 ! millert 1: /* $OpenBSD: rsh.c,v 1.34 2003/08/11 20:43:31 millert Exp $ */
1.4 deraadt 2:
1.1 deraadt 3: /*-
4: * Copyright (c) 1983, 1990 The Regents of the University of California.
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
1.32 millert 15: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
32: #ifndef lint
1.33 millert 33: static const char copyright[] =
1.1 deraadt 34: "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
35: All rights reserved.\n";
36: #endif /* not lint */
37:
38: #ifndef lint
1.33 millert 39: /*static const char sccsid[] = "from: @(#)rsh.c 5.24 (Berkeley) 7/1/91";*/
1.35 ! millert 40: static const char rcsid[] = "$OpenBSD: rsh.c,v 1.34 2003/08/11 20:43:31 millert Exp $";
1.1 deraadt 41: #endif /* not lint */
42:
43: #include <sys/types.h>
44: #include <sys/socket.h>
45: #include <sys/ioctl.h>
46: #include <sys/file.h>
47:
48: #include <netinet/in.h>
1.34 millert 49:
50: #include <err.h>
51: #include <errno.h>
1.1 deraadt 52: #include <netdb.h>
1.34 millert 53: #include <poll.h>
1.1 deraadt 54: #include <pwd.h>
55: #include <signal.h>
1.34 millert 56: #include <stdarg.h>
1.1 deraadt 57: #include <stdio.h>
1.17 art 58: #include <stdlib.h>
1.34 millert 59: #include <string.h>
1.17 art 60: #include <unistd.h>
1.34 millert 61:
1.1 deraadt 62: #include "pathnames.h"
63:
1.35 ! millert 64: __dead void usage(void);
1.29 deraadt 65: void sendsig(int);
66: char *copyargs(char **argv);
1.23 millert 67: void talk(int, sigset_t *, int, int);
1.17 art 68:
1.1 deraadt 69: /*
70: * rsh - remote shell
71: */
72: int rfd2;
73:
1.17 art 74: int
1.29 deraadt 75: main(int argc, char *argv[])
1.1 deraadt 76: {
77: struct passwd *pw;
78: struct servent *sp;
1.20 millert 79: sigset_t mask, omask;
1.28 mpech 80: int argoff, asrsh, ch, dflag, nflag, one, rem, uid;
1.35 ! millert 81: char *args, *host, *user;
1.28 mpech 82: pid_t pid = 0;
1.35 ! millert 83: extern char *__progname;
1.1 deraadt 84:
85: argoff = asrsh = dflag = nflag = 0;
86: one = 1;
87: host = user = NULL;
88:
89: /* if called as something other than "rsh", use it as the host name */
1.35 ! millert 90: if (strcmp(__progname, "rsh") != 0)
! 91: host = __progname;
1.1 deraadt 92: else
93: asrsh = 1;
94:
95: /* handle "rsh host flags" */
96: if (!host && argc > 2 && argv[1][0] != '-') {
97: host = argv[1];
98: argoff = 1;
99: }
100:
1.35 ! millert 101: while ((ch = getopt(argc - argoff, argv + argoff, "8KLdel:nw")) != -1)
1.1 deraadt 102: switch(ch) {
1.35 ! millert 103: case '8': /* -8KLew are ignored to allow rlogin aliases */
1.1 deraadt 104: case 'K':
1.35 ! millert 105: case 'L':
1.1 deraadt 106: case 'e':
107: case 'w':
108: break;
109: case 'd':
110: dflag = 1;
111: break;
112: case 'l':
113: user = optarg;
114: break;
115: case 'n':
116: nflag = 1;
117: break;
118: default:
119: usage();
120: }
121: optind += argoff;
122:
123: /* if haven't gotten a host yet, do so */
124: if (!host && !(host = argv[optind++]))
125: usage();
126:
1.26 millert 127: /* if no command, login to remote host via rlogin or telnet. */
1.1 deraadt 128: if (!argv[optind]) {
1.26 millert 129: seteuid(getuid());
130: setuid(getuid());
1.1 deraadt 131: if (asrsh)
132: *argv = "rlogin";
133: execv(_PATH_RLOGIN, argv);
1.26 millert 134: if (errno == ENOENT) {
135: if (asrsh)
136: *argv = "telnet";
137: execv(_PATH_TELNET, argv);
138: }
1.33 millert 139: errx(1, "can't exec %s", _PATH_TELNET);
1.1 deraadt 140: }
141:
142: argc -= optind;
143: argv += optind;
144:
1.33 millert 145: if (geteuid() != 0)
146: errx(1, "must be setuid root");
1.35 ! millert 147: if ((pw = getpwuid(uid = getuid())) == NULL)
1.33 millert 148: errx(1, "unknown user ID %u", uid);
1.35 ! millert 149: if (user == NULL)
1.1 deraadt 150: user = pw->pw_name;
151:
152: args = copyargs(argv);
153:
1.35 ! millert 154: if ((sp = getservbyname("shell", "tcp")) == NULL)
1.33 millert 155: errx(1, "shell/tcp: unknown service");
1.9 millert 156:
1.35 ! millert 157: (void)unsetenv("RSH"); /* no tricks with rcmd(3) */
1.1 deraadt 158:
1.18 itojun 159: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
160: PF_UNSPEC);
1.1 deraadt 161: if (rem < 0)
162: exit(1);
163:
1.33 millert 164: if (rfd2 < 0)
165: errx(1, "can't establish stderr");
1.1 deraadt 166: if (dflag) {
167: if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
168: sizeof(one)) < 0)
1.33 millert 169: warn("setsockopt");
1.1 deraadt 170: if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
171: sizeof(one)) < 0)
1.33 millert 172: warn("setsockopt");
1.1 deraadt 173: }
174:
1.10 tholo 175: (void)seteuid(uid);
1.1 deraadt 176: (void)setuid(uid);
1.20 millert 177: sigemptyset(&mask);
178: sigaddset(&mask, SIGINT);
179: sigaddset(&mask, SIGQUIT);
180: sigaddset(&mask, SIGTERM);
181: sigprocmask(SIG_BLOCK, &mask, &omask);
1.1 deraadt 182: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
183: (void)signal(SIGINT, sendsig);
184: if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
185: (void)signal(SIGQUIT, sendsig);
186: if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
187: (void)signal(SIGTERM, sendsig);
188:
189: if (!nflag) {
1.33 millert 190: if ((pid = fork()) < 0)
191: err(1, "fork");
1.1 deraadt 192: }
193:
1.35 ! millert 194: (void)ioctl(rfd2, FIONBIO, &one);
! 195: (void)ioctl(rem, FIONBIO, &one);
1.1 deraadt 196:
1.20 millert 197: talk(nflag, &omask, pid, rem);
1.1 deraadt 198:
199: if (!nflag)
200: (void)kill(pid, SIGKILL);
1.17 art 201:
202: return 0;
1.1 deraadt 203: }
204:
1.17 art 205: void
1.29 deraadt 206: talk(int nflag, sigset_t *omask, pid_t pid, int rem)
1.1 deraadt 207: {
1.22 mpech 208: int cc, wc;
209: char *bp;
1.34 millert 210: struct pollfd pfd[2];
1.1 deraadt 211: char buf[BUFSIZ];
212:
213: if (!nflag && pid == 0) {
214: (void)close(rfd2);
215:
216: reread: errno = 0;
1.34 millert 217: if ((cc = read(STDIN_FILENO, buf, sizeof buf)) <= 0)
1.1 deraadt 218: goto done;
219: bp = buf;
220:
1.34 millert 221: pfd[0].fd = rem;
222: pfd[0].events = POLLOUT;
223: rewrite:
224: if (poll(pfd, 1, INFTIM) < 0) {
1.33 millert 225: if (errno != EINTR)
1.34 millert 226: err(1, "poll");
1.1 deraadt 227: goto rewrite;
228: }
1.35 ! millert 229: if (pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL))
! 230: err(1, "poll");
! 231: wc = write(rem, bp, cc);
1.1 deraadt 232: if (wc < 0) {
233: if (errno == EWOULDBLOCK)
234: goto rewrite;
235: goto done;
236: }
237: bp += wc;
238: cc -= wc;
239: if (cc == 0)
240: goto reread;
241: goto rewrite;
242: done:
243: (void)shutdown(rem, 1);
244: exit(0);
245: }
246:
1.21 deraadt 247: sigprocmask(SIG_SETMASK, omask, NULL);
1.34 millert 248: pfd[1].fd = rfd2;
249: pfd[1].events = POLLIN;
250: pfd[0].fd = rem;
251: pfd[0].events = POLLIN;
1.1 deraadt 252: do {
1.34 millert 253: if (poll(pfd, 2, INFTIM) < 0) {
1.33 millert 254: if (errno != EINTR)
1.34 millert 255: err(1, "poll");
1.1 deraadt 256: continue;
257: }
1.35 ! millert 258: if ((pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL)) ||
! 259: (pfd[1].revents & (POLLERR|POLLHUP|POLLNVAL)))
! 260: err(1, "poll");
1.34 millert 261: if (pfd[1].revents & POLLIN) {
1.1 deraadt 262: errno = 0;
1.35 ! millert 263: cc = read(rfd2, buf, sizeof buf);
1.1 deraadt 264: if (cc <= 0) {
265: if (errno != EWOULDBLOCK)
1.34 millert 266: pfd[1].revents = 0;
1.1 deraadt 267: } else
1.34 millert 268: (void)write(STDERR_FILENO, buf, cc);
1.1 deraadt 269: }
1.34 millert 270: if (pfd[0].revents & POLLIN) {
1.1 deraadt 271: errno = 0;
1.35 ! millert 272: cc = read(rem, buf, sizeof buf);
1.1 deraadt 273: if (cc <= 0) {
274: if (errno != EWOULDBLOCK)
1.34 millert 275: pfd[0].revents = 0;
1.1 deraadt 276: } else
1.34 millert 277: (void)write(STDOUT_FILENO, buf, cc);
1.1 deraadt 278: }
1.34 millert 279: } while ((pfd[0].revents & POLLIN) || (pfd[1].revents & POLLIN));
1.1 deraadt 280: }
281:
282: void
1.29 deraadt 283: sendsig(int signo)
1.1 deraadt 284: {
1.16 deraadt 285: int save_errno = errno;
286:
1.35 ! millert 287: (void)write(rfd2, &signo, 1);
1.16 deraadt 288: errno = save_errno;
1.1 deraadt 289: }
290:
291: char *
1.29 deraadt 292: copyargs(char **argv)
1.1 deraadt 293: {
1.29 deraadt 294: char **ap, *p, *args;
1.31 millert 295: size_t cc, len;
1.1 deraadt 296:
297: cc = 0;
298: for (ap = argv; *ap; ++ap)
299: cc += strlen(*ap) + 1;
1.31 millert 300: if ((args = malloc(cc)) == NULL)
301: err(1, NULL);
1.1 deraadt 302: for (p = args, ap = argv; *ap; ++ap) {
1.31 millert 303: len = strlcpy(p, *ap, cc);
304: if (len >= cc)
305: errx(1, "copyargs overflow");
306: p += len;
307: cc -= len;
308: if (ap[1]) {
1.1 deraadt 309: *p++ = ' ';
1.31 millert 310: cc--;
311: }
1.1 deraadt 312: }
313: return(args);
314: }
315:
1.35 ! millert 316: __dead void
1.17 art 317: usage(void)
1.1 deraadt 318: {
319: (void)fprintf(stderr,
1.35 ! millert 320: "usage: rsh [-Kdn] [-l username] hostname [command]\n");
1.1 deraadt 321: exit(1);
322: }