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