rsh.c revision 1.5 1 /* $NetBSD: rsh.c,v 1.5 1997/02/16 15:01:05 mrg Exp $ */
2
3 /*-
4 * Copyright (c) 1983, 1990, 1993, 1994
5 * The Regents of the University of California. 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.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #ifndef lint
37 static char copyright[] =
38 "@(#) Copyright (c) 1983, 1990, 1993, 1994\n\
39 The Regents of the University of California. All rights reserved.\n";
40 #endif /* not lint */
41
42 #ifndef lint
43 /*static char sccsid[] = "from: @(#)rsh.c 8.4 (Berkeley) 4/29/95";*/
44 static char rcsid[] = "$NetBSD: rsh.c,v 1.5 1997/02/16 15:01:05 mrg Exp $";
45 #endif /* not lint */
46
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <sys/ioctl.h>
50 #include <sys/file.h>
51
52 #include <netinet/in.h>
53 #include <netdb.h>
54
55 #include <err.h>
56 #include <errno.h>
57 #include <pwd.h>
58 #include <signal.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63 #include <varargs.h>
64
65 #include "pathnames.h"
66
67 #ifdef KERBEROS
68 #include <kerberosIV/des.h>
69 #include <kerberosIV/krb.h>
70
71 CREDENTIALS cred;
72 Key_schedule schedule;
73 int use_kerberos = 1, doencrypt;
74 char dst_realm_buf[REALM_SZ], *dest_realm;
75 extern char *krb_realmofhost();
76 #endif
77
78 /*
79 * rsh - remote shell
80 */
81 int rfd2;
82
83 char *copyargs __P((char **));
84 void sendsig __P((int));
85 void talk __P((int, long, pid_t, int));
86 void usage __P((void));
87 void warning __P(());
88
89 int
90 main(argc, argv)
91 int argc;
92 char **argv;
93 {
94 struct passwd *pw;
95 struct servent *sp;
96 long omask;
97 int argoff, asrsh, ch, dflag, nflag, one, rem;
98 pid_t pid;
99 uid_t uid;
100 char *args, *host, *p, *user;
101
102 argoff = asrsh = dflag = nflag = 0;
103 one = 1;
104 host = user = NULL;
105
106 /* if called as something other than "rsh", use it as the host name */
107 if (p = strrchr(argv[0], '/'))
108 ++p;
109 else
110 p = argv[0];
111 if (strcmp(p, "rsh"))
112 host = p;
113 else
114 asrsh = 1;
115
116 /* handle "rsh host flags" */
117 if (!host && argc > 2 && argv[1][0] != '-') {
118 host = argv[1];
119 argoff = 1;
120 }
121
122 #ifdef KERBEROS
123 #ifdef CRYPT
124 #define OPTIONS "8KLdek:l:nwx"
125 #else
126 #define OPTIONS "8KLdek:l:nw"
127 #endif
128 #else
129 #define OPTIONS "8KLdel:nw"
130 #endif
131 while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
132 switch(ch) {
133 case 'K':
134 #ifdef KERBEROS
135 use_kerberos = 0;
136 #endif
137 break;
138 case 'L': /* -8Lew are ignored to allow rlogin aliases */
139 case 'e':
140 case 'w':
141 case '8':
142 break;
143 case 'd':
144 dflag = 1;
145 break;
146 case 'l':
147 user = optarg;
148 break;
149 #ifdef KERBEROS
150 case 'k':
151 dest_realm = dst_realm_buf;
152 strncpy(dest_realm, optarg, REALM_SZ);
153 break;
154 #endif
155 case 'n':
156 nflag = 1;
157 break;
158 #ifdef KERBEROS
159 #ifdef CRYPT
160 case 'x':
161 doencrypt = 1;
162 des_set_key(cred.session, schedule);
163 break;
164 #endif
165 #endif
166 case '?':
167 default:
168 usage();
169 }
170 optind += argoff;
171
172 /* if haven't gotten a host yet, do so */
173 if (!host && !(host = argv[optind++]))
174 usage();
175
176 /* if no further arguments, must have been called as rlogin. */
177 if (!argv[optind]) {
178 if (asrsh)
179 *argv = "rlogin";
180 execv(_PATH_RLOGIN, argv);
181 err(1, "can't exec %s", _PATH_RLOGIN);
182 }
183
184 argc -= optind;
185 argv += optind;
186
187 if (!(pw = getpwuid(uid = getuid())))
188 errx(1, "unknown user id");
189 /* Accept user1@host format, though "-l user2" overrides user1 */
190 p = strchr(host, '@');
191 if (p) {
192 *p = '\0';
193 if (!user && p > host)
194 user = host;
195 host = p + 1;
196 if (*host == '\0')
197 usage();
198 }
199 if (!user)
200 user = pw->pw_name;
201
202 #ifdef KERBEROS
203 #ifdef CRYPT
204 /* -x turns off -n */
205 if (doencrypt)
206 nflag = 0;
207 #endif
208 #endif
209
210 args = copyargs(argv);
211
212 sp = NULL;
213 #ifdef KERBEROS
214 if (use_kerberos) {
215 sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
216 if (sp == NULL) {
217 use_kerberos = 0;
218 warning("can't get entry for %s/tcp service",
219 doencrypt ? "ekshell" : "kshell");
220 }
221 }
222 #endif
223 if (sp == NULL)
224 sp = getservbyname("shell", "tcp");
225 if (sp == NULL)
226 errx(1, "shell/tcp: unknown service");
227
228 #ifdef KERBEROS
229 try_connect:
230 if (use_kerberos) {
231 struct hostent *hp;
232
233 /* fully qualify hostname (needed for krb_realmofhost) */
234 hp = gethostbyname(host);
235 if (hp != NULL && !(host = strdup(hp->h_name)))
236 err(1, NULL);
237
238 rem = KSUCCESS;
239 errno = 0;
240 if (dest_realm == NULL)
241 dest_realm = krb_realmofhost(host);
242
243 #ifdef CRYPT
244 if (doencrypt)
245 rem = krcmd_mutual(&host, sp->s_port, user, args,
246 &rfd2, dest_realm, &cred, schedule);
247 else
248 #endif
249 rem = krcmd(&host, sp->s_port, user, args, &rfd2,
250 dest_realm);
251 if (rem < 0) {
252 use_kerberos = 0;
253 sp = getservbyname("shell", "tcp");
254 if (sp == NULL)
255 errx(1, "shell/tcp: unknown service");
256 if (errno == ECONNREFUSED)
257 warning("remote host doesn't support Kerberos");
258 if (errno == ENOENT)
259 warning("can't provide Kerberos auth data");
260 goto try_connect;
261 }
262 } else {
263 if (doencrypt)
264 errx(1, "the -x flag requires Kerberos authentication");
265 rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
266 }
267 #else
268 rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
269 #endif
270
271 if (rem < 0)
272 exit(1);
273
274 if (rfd2 < 0)
275 errx(1, "can't establish stderr");
276 if (dflag) {
277 if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
278 sizeof(one)) < 0)
279 warn("setsockopt");
280 if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
281 sizeof(one)) < 0)
282 warn("setsockopt");
283 }
284
285 (void)setuid(uid);
286 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
287 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
288 (void)signal(SIGINT, sendsig);
289 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
290 (void)signal(SIGQUIT, sendsig);
291 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
292 (void)signal(SIGTERM, sendsig);
293
294 if (!nflag) {
295 pid = fork();
296 if (pid < 0)
297 err(1, "fork");
298 }
299
300 #ifdef KERBEROS
301 #ifdef CRYPT
302 if (!doencrypt)
303 #endif
304 #endif
305 {
306 (void)ioctl(rfd2, FIONBIO, &one);
307 (void)ioctl(rem, FIONBIO, &one);
308 }
309
310 talk(nflag, omask, pid, rem);
311
312 if (!nflag)
313 (void)kill(pid, SIGKILL);
314 exit(0);
315 }
316
317 void
318 talk(nflag, omask, pid, rem)
319 int nflag;
320 long omask;
321 pid_t pid;
322 int rem;
323 {
324 int cc, wc;
325 fd_set readfrom, ready, rembits;
326 char *bp, buf[BUFSIZ];
327
328 if (!nflag && pid == 0) {
329 (void)close(rfd2);
330
331 reread: errno = 0;
332 if ((cc = read(0, buf, sizeof buf)) <= 0)
333 goto done;
334 bp = buf;
335
336 rewrite:
337 FD_ZERO(&rembits);
338 FD_SET(rem, &rembits);
339 if (select(16, 0, &rembits, 0, 0) < 0) {
340 if (errno != EINTR)
341 err(1, "select");
342 goto rewrite;
343 }
344 if (!FD_ISSET(rem, &rembits))
345 goto rewrite;
346 #ifdef KERBEROS
347 #ifdef CRYPT
348 if (doencrypt)
349 wc = des_write(rem, bp, cc);
350 else
351 #endif
352 #endif
353 wc = write(rem, bp, cc);
354 if (wc < 0) {
355 if (errno == EWOULDBLOCK)
356 goto rewrite;
357 goto done;
358 }
359 bp += wc;
360 cc -= wc;
361 if (cc == 0)
362 goto reread;
363 goto rewrite;
364 done:
365 (void)shutdown(rem, 1);
366 exit(0);
367 }
368
369 (void)sigsetmask(omask);
370 FD_ZERO(&readfrom);
371 FD_SET(rfd2, &readfrom);
372 FD_SET(rem, &readfrom);
373 do {
374 ready = readfrom;
375 if (select(16, &ready, 0, 0, 0) < 0) {
376 if (errno != EINTR)
377 err(1, "select");
378 continue;
379 }
380 if (FD_ISSET(rfd2, &ready)) {
381 errno = 0;
382 #ifdef KERBEROS
383 #ifdef CRYPT
384 if (doencrypt)
385 cc = des_read(rfd2, buf, sizeof buf);
386 else
387 #endif
388 #endif
389 cc = read(rfd2, buf, sizeof buf);
390 if (cc <= 0) {
391 if (errno != EWOULDBLOCK)
392 FD_CLR(rfd2, &readfrom);
393 } else
394 (void)write(2, buf, cc);
395 }
396 if (FD_ISSET(rem, &ready)) {
397 errno = 0;
398 #ifdef KERBEROS
399 #ifdef CRYPT
400 if (doencrypt)
401 cc = des_read(rem, buf, sizeof buf);
402 else
403 #endif
404 #endif
405 cc = read(rem, buf, sizeof buf);
406 if (cc <= 0) {
407 if (errno != EWOULDBLOCK)
408 FD_CLR(rem, &readfrom);
409 } else
410 (void)write(1, buf, cc);
411 }
412 } while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom));
413 }
414
415 void
416 sendsig(sig)
417 int sig;
418 {
419 char signo;
420
421 signo = sig;
422 #ifdef KERBEROS
423 #ifdef CRYPT
424 if (doencrypt)
425 (void)des_write(rfd2, &signo, 1);
426 else
427 #endif
428 #endif
429 (void)write(rfd2, &signo, 1);
430 }
431
432 #ifdef KERBEROS
433 /* VARARGS */
434 void
435 warning(va_alist)
436 va_dcl
437 {
438 va_list ap;
439 char *fmt;
440
441 (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
442 va_start(ap);
443 fmt = va_arg(ap, char *);
444 vfprintf(stderr, fmt, ap);
445 va_end(ap);
446 (void)fprintf(stderr, ".\n");
447 }
448 #endif
449
450 char *
451 copyargs(argv)
452 char **argv;
453 {
454 int cc;
455 char **ap, *args, *p;
456
457 cc = 0;
458 for (ap = argv; *ap; ++ap)
459 cc += strlen(*ap) + 1;
460 if (!(args = malloc((u_int)cc)))
461 err(1, NULL);
462 for (p = args, ap = argv; *ap; ++ap) {
463 (void)strcpy(p, *ap);
464 for (p = strcpy(p, *ap); *p; ++p);
465 if (ap[1])
466 *p++ = ' ';
467 }
468 return (args);
469 }
470
471 void
472 usage()
473 {
474
475 (void)fprintf(stderr,
476 "usage: rsh [-nd%s]%s[-l login] [login@]host [command]\n",
477 #ifdef KERBEROS
478 #ifdef CRYPT
479 "x", " [-k realm] ");
480 #else
481 "", " [-k realm] ");
482 #endif
483 #else
484 "", " ");
485 #endif
486 exit(1);
487 }
488