Annotation of src/usr.bin/rsh/rsh.c, Revision 1.37
1.37 ! deraadt 1: /* $OpenBSD: rsh.c,v 1.36 2004/01/17 21:42:48 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.37 ! deraadt 40: static const char rcsid[] = "$OpenBSD: rsh.c,v 1.36 2004/01/17 21:42:48 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.37 ! deraadt 80: int argoff = 0, asrsh = 0, ch, dflag = 0, nflag = 0, one = 1, rem, uid;
! 81: char *args, *host = NULL, *user = NULL;
1.28 mpech 82: pid_t pid = 0;
1.35 millert 83: extern char *__progname;
1.1 deraadt 84:
85: /* if called as something other than "rsh", use it as the host name */
1.35 millert 86: if (strcmp(__progname, "rsh") != 0)
87: host = __progname;
1.1 deraadt 88: else
89: asrsh = 1;
90:
91: /* handle "rsh host flags" */
92: if (!host && argc > 2 && argv[1][0] != '-') {
93: host = argv[1];
94: argoff = 1;
95: }
96:
1.35 millert 97: while ((ch = getopt(argc - argoff, argv + argoff, "8KLdel:nw")) != -1)
1.1 deraadt 98: switch(ch) {
1.35 millert 99: case '8': /* -8KLew are ignored to allow rlogin aliases */
1.1 deraadt 100: case 'K':
1.35 millert 101: case 'L':
1.1 deraadt 102: case 'e':
103: case 'w':
104: break;
105: case 'd':
106: dflag = 1;
107: break;
108: case 'l':
109: user = optarg;
110: break;
111: case 'n':
112: nflag = 1;
113: break;
114: default:
115: usage();
116: }
117: optind += argoff;
118:
119: /* if haven't gotten a host yet, do so */
120: if (!host && !(host = argv[optind++]))
121: usage();
122:
1.36 millert 123: /* if no command, login to remote host via ssh. */
1.1 deraadt 124: if (!argv[optind]) {
1.26 millert 125: seteuid(getuid());
126: setuid(getuid());
1.1 deraadt 127: if (asrsh)
1.36 millert 128: *argv = "ssh";
129: execv(_PATH_SSH, argv);
130: errx(1, "can't exec %s", _PATH_SSH);
1.1 deraadt 131: }
132:
133: argc -= optind;
134: argv += optind;
135:
1.33 millert 136: if (geteuid() != 0)
137: errx(1, "must be setuid root");
1.35 millert 138: if ((pw = getpwuid(uid = getuid())) == NULL)
1.33 millert 139: errx(1, "unknown user ID %u", uid);
1.35 millert 140: if (user == NULL)
1.1 deraadt 141: user = pw->pw_name;
142:
143: args = copyargs(argv);
144:
1.35 millert 145: if ((sp = getservbyname("shell", "tcp")) == NULL)
1.33 millert 146: errx(1, "shell/tcp: unknown service");
1.9 millert 147:
1.35 millert 148: (void)unsetenv("RSH"); /* no tricks with rcmd(3) */
1.1 deraadt 149:
1.18 itojun 150: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
151: PF_UNSPEC);
1.1 deraadt 152: if (rem < 0)
153: exit(1);
1.33 millert 154: if (rfd2 < 0)
155: errx(1, "can't establish stderr");
1.37 ! deraadt 156:
! 157: (void)seteuid(uid);
! 158: (void)setuid(uid);
! 159:
1.1 deraadt 160: if (dflag) {
161: if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
162: sizeof(one)) < 0)
1.33 millert 163: warn("setsockopt");
1.1 deraadt 164: if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
165: sizeof(one)) < 0)
1.33 millert 166: warn("setsockopt");
1.1 deraadt 167: }
1.20 millert 168: sigemptyset(&mask);
169: sigaddset(&mask, SIGINT);
170: sigaddset(&mask, SIGQUIT);
171: sigaddset(&mask, SIGTERM);
172: sigprocmask(SIG_BLOCK, &mask, &omask);
1.1 deraadt 173: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
174: (void)signal(SIGINT, sendsig);
175: if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
176: (void)signal(SIGQUIT, sendsig);
177: if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
178: (void)signal(SIGTERM, sendsig);
179:
180: if (!nflag) {
1.33 millert 181: if ((pid = fork()) < 0)
182: err(1, "fork");
1.1 deraadt 183: }
184:
1.35 millert 185: (void)ioctl(rfd2, FIONBIO, &one);
186: (void)ioctl(rem, FIONBIO, &one);
1.1 deraadt 187:
1.20 millert 188: talk(nflag, &omask, pid, rem);
1.1 deraadt 189:
190: if (!nflag)
191: (void)kill(pid, SIGKILL);
1.17 art 192:
193: return 0;
1.1 deraadt 194: }
195:
1.17 art 196: void
1.29 deraadt 197: talk(int nflag, sigset_t *omask, pid_t pid, int rem)
1.1 deraadt 198: {
1.22 mpech 199: int cc, wc;
200: char *bp;
1.34 millert 201: struct pollfd pfd[2];
1.1 deraadt 202: char buf[BUFSIZ];
203:
204: if (!nflag && pid == 0) {
205: (void)close(rfd2);
206:
207: reread: errno = 0;
1.34 millert 208: if ((cc = read(STDIN_FILENO, buf, sizeof buf)) <= 0)
1.1 deraadt 209: goto done;
210: bp = buf;
211:
1.34 millert 212: pfd[0].fd = rem;
213: pfd[0].events = POLLOUT;
214: rewrite:
215: if (poll(pfd, 1, INFTIM) < 0) {
1.33 millert 216: if (errno != EINTR)
1.34 millert 217: err(1, "poll");
1.1 deraadt 218: goto rewrite;
219: }
1.35 millert 220: if (pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL))
221: err(1, "poll");
222: wc = write(rem, bp, cc);
1.1 deraadt 223: if (wc < 0) {
224: if (errno == EWOULDBLOCK)
225: goto rewrite;
226: goto done;
227: }
228: bp += wc;
229: cc -= wc;
230: if (cc == 0)
231: goto reread;
232: goto rewrite;
233: done:
234: (void)shutdown(rem, 1);
235: exit(0);
236: }
237:
1.21 deraadt 238: sigprocmask(SIG_SETMASK, omask, NULL);
1.34 millert 239: pfd[1].fd = rfd2;
240: pfd[1].events = POLLIN;
241: pfd[0].fd = rem;
242: pfd[0].events = POLLIN;
1.1 deraadt 243: do {
1.34 millert 244: if (poll(pfd, 2, INFTIM) < 0) {
1.33 millert 245: if (errno != EINTR)
1.34 millert 246: err(1, "poll");
1.1 deraadt 247: continue;
248: }
1.35 millert 249: if ((pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL)) ||
250: (pfd[1].revents & (POLLERR|POLLHUP|POLLNVAL)))
251: err(1, "poll");
1.34 millert 252: if (pfd[1].revents & POLLIN) {
1.1 deraadt 253: errno = 0;
1.35 millert 254: cc = read(rfd2, buf, sizeof buf);
1.1 deraadt 255: if (cc <= 0) {
256: if (errno != EWOULDBLOCK)
1.34 millert 257: pfd[1].revents = 0;
1.1 deraadt 258: } else
1.34 millert 259: (void)write(STDERR_FILENO, buf, cc);
1.1 deraadt 260: }
1.34 millert 261: if (pfd[0].revents & POLLIN) {
1.1 deraadt 262: errno = 0;
1.35 millert 263: cc = read(rem, buf, sizeof buf);
1.1 deraadt 264: if (cc <= 0) {
265: if (errno != EWOULDBLOCK)
1.34 millert 266: pfd[0].revents = 0;
1.1 deraadt 267: } else
1.34 millert 268: (void)write(STDOUT_FILENO, buf, cc);
1.1 deraadt 269: }
1.34 millert 270: } while ((pfd[0].revents & POLLIN) || (pfd[1].revents & POLLIN));
1.1 deraadt 271: }
272:
273: void
1.29 deraadt 274: sendsig(int signo)
1.1 deraadt 275: {
1.16 deraadt 276: int save_errno = errno;
277:
1.35 millert 278: (void)write(rfd2, &signo, 1);
1.16 deraadt 279: errno = save_errno;
1.1 deraadt 280: }
281:
282: char *
1.29 deraadt 283: copyargs(char **argv)
1.1 deraadt 284: {
1.29 deraadt 285: char **ap, *p, *args;
1.31 millert 286: size_t cc, len;
1.1 deraadt 287:
288: cc = 0;
289: for (ap = argv; *ap; ++ap)
290: cc += strlen(*ap) + 1;
1.31 millert 291: if ((args = malloc(cc)) == NULL)
292: err(1, NULL);
1.1 deraadt 293: for (p = args, ap = argv; *ap; ++ap) {
1.31 millert 294: len = strlcpy(p, *ap, cc);
295: if (len >= cc)
296: errx(1, "copyargs overflow");
297: p += len;
298: cc -= len;
299: if (ap[1]) {
1.1 deraadt 300: *p++ = ' ';
1.31 millert 301: cc--;
302: }
1.1 deraadt 303: }
304: return(args);
305: }
306:
1.35 millert 307: __dead void
1.17 art 308: usage(void)
1.1 deraadt 309: {
310: (void)fprintf(stderr,
1.35 millert 311: "usage: rsh [-Kdn] [-l username] hostname [command]\n");
1.1 deraadt 312: exit(1);
313: }