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