rsh.c revision 1.4 1 /* $NetBSD: rsh.c,v 1.4 1997/01/09 20:21:15 tls Exp $ */
2
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.
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 char copyright[] =
38 "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
39 All rights reserved.\n";
40 #endif /* not lint */
41
42 #ifndef lint
43 /*static char sccsid[] = "from: @(#)rsh.c 5.24 (Berkeley) 7/1/91";*/
44 static char rcsid[] = "$NetBSD: rsh.c,v 1.4 1997/01/09 20:21:15 tls Exp $";
45 #endif /* not lint */
46
47 /*
48 * $Source: /tank/opengrok/rsync2/NetBSD/src/usr.bin/rsh/rsh.c,v $
49 * $Header: /tank/opengrok/rsync2/NetBSD/src/usr.bin/rsh/rsh.c,v 1.4 1997/01/09 20:21:15 tls Exp $
50 */
51
52 #include <sys/types.h>
53 #include <sys/socket.h>
54 #include <sys/ioctl.h>
55 #include <sys/file.h>
56
57 #include <netinet/in.h>
58 #include <netdb.h>
59
60 #include <pwd.h>
61 #include <signal.h>
62 #include <stdio.h>
63 #include <errno.h>
64 #include <string.h>
65 #include <varargs.h>
66 #include "pathnames.h"
67
68 #ifdef KERBEROS
69 #include <kerberosIV/des.h>
70 #include <kerberosIV/krb.h>
71
72 CREDENTIALS cred;
73 Key_schedule schedule;
74 int use_kerberos = 1, doencrypt;
75 char dst_realm_buf[REALM_SZ], *dest_realm;
76 extern char *krb_realmofhost();
77 #endif
78
79 /*
80 * rsh - remote shell
81 */
82 extern int errno;
83 int rfd2;
84
85 main(argc, argv)
86 int argc;
87 char **argv;
88 {
89 extern char *optarg;
90 extern int optind;
91 struct passwd *pw;
92 struct servent *sp;
93 long omask;
94 int argoff, asrsh, ch, dflag, nflag, one, pid, rem, uid;
95 register char *p;
96 char *args, *host, *user, *copyargs();
97 void sendsig();
98
99 argoff = asrsh = dflag = nflag = 0;
100 one = 1;
101 host = user = NULL;
102
103 /* if called as something other than "rsh", use it as the host name */
104 if (p = rindex(argv[0], '/'))
105 ++p;
106 else
107 p = argv[0];
108 if (strcmp(p, "rsh"))
109 host = p;
110 else
111 asrsh = 1;
112
113 /* handle "rsh host flags" */
114 if (!host && argc > 2 && argv[1][0] != '-') {
115 host = argv[1];
116 argoff = 1;
117 }
118
119 #ifdef KERBEROS
120 #ifdef CRYPT
121 #define OPTIONS "8KLdek:l:nwx"
122 #else
123 #define OPTIONS "8KLdek:l:nw"
124 #endif
125 #else
126 #define OPTIONS "8KLdel:nw"
127 #endif
128 while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
129 switch(ch) {
130 case 'K':
131 #ifdef KERBEROS
132 use_kerberos = 0;
133 #endif
134 break;
135 case 'L': /* -8Lew are ignored to allow rlogin aliases */
136 case 'e':
137 case 'w':
138 case '8':
139 break;
140 case 'd':
141 dflag = 1;
142 break;
143 case 'l':
144 user = optarg;
145 break;
146 #ifdef KERBEROS
147 case 'k':
148 dest_realm = dst_realm_buf;
149 strncpy(dest_realm, optarg, REALM_SZ);
150 break;
151 #endif
152 case 'n':
153 nflag = 1;
154 break;
155 #ifdef KERBEROS
156 #ifdef CRYPT
157 case 'x':
158 doencrypt = 1;
159 des_set_key(cred.session, schedule);
160 break;
161 #endif
162 #endif
163 case '?':
164 default:
165 usage();
166 }
167 optind += argoff;
168
169 /* if haven't gotten a host yet, do so */
170 if (!host && !(host = argv[optind++]))
171 usage();
172
173 /* if no further arguments, must have been called as rlogin. */
174 if (!argv[optind]) {
175 if (asrsh)
176 *argv = "rlogin";
177 execv(_PATH_RLOGIN, argv);
178 (void)fprintf(stderr, "rsh: can't exec %s.\n", _PATH_RLOGIN);
179 exit(1);
180 }
181
182 argc -= optind;
183 argv += optind;
184
185 if (!(pw = getpwuid(uid = getuid()))) {
186 (void)fprintf(stderr, "rsh: unknown user id.\n");
187 exit(1);
188 }
189 if (!user)
190 user = pw->pw_name;
191
192 #ifdef KERBEROS
193 #ifdef CRYPT
194 /* -x turns off -n */
195 if (doencrypt)
196 nflag = 0;
197 #endif
198 #endif
199
200 args = copyargs(argv);
201
202 sp = NULL;
203 #ifdef KERBEROS
204 if (use_kerberos) {
205 sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
206 if (sp == NULL) {
207 use_kerberos = 0;
208 warning("can't get entry for %s/tcp service",
209 doencrypt ? "ekshell" : "kshell");
210 }
211 }
212 #endif
213 if (sp == NULL)
214 sp = getservbyname("shell", "tcp");
215 if (sp == NULL) {
216 (void)fprintf(stderr, "rsh: shell/tcp: unknown service.\n");
217 exit(1);
218 }
219
220 #ifdef KERBEROS
221 try_connect:
222 if (use_kerberos) {
223 rem = KSUCCESS;
224 errno = 0;
225 if (dest_realm == NULL)
226 dest_realm = krb_realmofhost(host);
227
228 #ifdef CRYPT
229 if (doencrypt)
230 rem = krcmd_mutual(&host, sp->s_port, user, args,
231 &rfd2, dest_realm, &cred, schedule);
232 else
233 #endif
234 rem = krcmd(&host, sp->s_port, user, args, &rfd2,
235 dest_realm);
236 if (rem < 0) {
237 use_kerberos = 0;
238 sp = getservbyname("shell", "tcp");
239 if (sp == NULL) {
240 (void)fprintf(stderr,
241 "rsh: unknown service shell/tcp.\n");
242 exit(1);
243 }
244 if (errno == ECONNREFUSED)
245 warning("remote host doesn't support Kerberos");
246 if (errno == ENOENT)
247 warning("can't provide Kerberos auth data");
248 goto try_connect;
249 }
250 } else {
251 if (doencrypt) {
252 (void)fprintf(stderr,
253 "rsh: the -x flag requires Kerberos authentication.\n");
254 exit(1);
255 }
256 rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
257 }
258 #else
259 rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
260 #endif
261
262 if (rem < 0)
263 exit(1);
264
265 if (rfd2 < 0) {
266 (void)fprintf(stderr, "rsh: can't establish stderr.\n");
267 exit(1);
268 }
269 if (dflag) {
270 if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
271 sizeof(one)) < 0)
272 (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
273 strerror(errno));
274 if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
275 sizeof(one)) < 0)
276 (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
277 strerror(errno));
278 }
279
280 (void)setuid(uid);
281 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
282 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
283 (void)signal(SIGINT, sendsig);
284 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
285 (void)signal(SIGQUIT, sendsig);
286 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
287 (void)signal(SIGTERM, sendsig);
288
289 if (!nflag) {
290 pid = fork();
291 if (pid < 0) {
292 (void)fprintf(stderr,
293 "rsh: fork: %s.\n", strerror(errno));
294 exit(1);
295 }
296 }
297
298 #ifdef KERBEROS
299 #ifdef CRYPT
300 if (!doencrypt)
301 #endif
302 #endif
303 {
304 (void)ioctl(rfd2, FIONBIO, &one);
305 (void)ioctl(rem, FIONBIO, &one);
306 }
307
308 talk(nflag, omask, pid, rem);
309
310 if (!nflag)
311 (void)kill(pid, SIGKILL);
312 exit(0);
313 }
314
315 talk(nflag, omask, pid, rem)
316 int nflag, pid;
317 long omask;
318 register int rem;
319 {
320 register int cc, wc;
321 register char *bp;
322 int readfrom, ready, rembits;
323 char buf[BUFSIZ];
324
325 if (!nflag && pid == 0) {
326 (void)close(rfd2);
327
328 reread: errno = 0;
329 if ((cc = read(0, buf, sizeof buf)) <= 0)
330 goto done;
331 bp = buf;
332
333 rewrite: rembits = 1 << rem;
334 if (select(16, 0, &rembits, 0, 0) < 0) {
335 if (errno != EINTR) {
336 (void)fprintf(stderr,
337 "rsh: select: %s.\n", strerror(errno));
338 exit(1);
339 }
340 goto rewrite;
341 }
342 if ((rembits & (1 << rem)) == 0)
343 goto rewrite;
344 #ifdef KERBEROS
345 #ifdef CRYPT
346 if (doencrypt)
347 wc = des_write(rem, bp, cc);
348 else
349 #endif
350 #endif
351 wc = write(rem, bp, cc);
352 if (wc < 0) {
353 if (errno == EWOULDBLOCK)
354 goto rewrite;
355 goto done;
356 }
357 bp += wc;
358 cc -= wc;
359 if (cc == 0)
360 goto reread;
361 goto rewrite;
362 done:
363 (void)shutdown(rem, 1);
364 exit(0);
365 }
366
367 (void)sigsetmask(omask);
368 readfrom = (1 << rfd2) | (1 << rem);
369 do {
370 ready = readfrom;
371 if (select(16, &ready, 0, 0, 0) < 0) {
372 if (errno != EINTR) {
373 (void)fprintf(stderr,
374 "rsh: select: %s.\n", strerror(errno));
375 exit(1);
376 }
377 continue;
378 }
379 if (ready & (1 << rfd2)) {
380 errno = 0;
381 #ifdef KERBEROS
382 #ifdef CRYPT
383 if (doencrypt)
384 cc = des_read(rfd2, buf, sizeof buf);
385 else
386 #endif
387 #endif
388 cc = read(rfd2, buf, sizeof buf);
389 if (cc <= 0) {
390 if (errno != EWOULDBLOCK)
391 readfrom &= ~(1 << rfd2);
392 } else
393 (void)write(2, buf, cc);
394 }
395 if (ready & (1 << rem)) {
396 errno = 0;
397 #ifdef KERBEROS
398 #ifdef CRYPT
399 if (doencrypt)
400 cc = des_read(rem, buf, sizeof buf);
401 else
402 #endif
403 #endif
404 cc = read(rem, buf, sizeof buf);
405 if (cc <= 0) {
406 if (errno != EWOULDBLOCK)
407 readfrom &= ~(1 << rem);
408 } else
409 (void)write(1, buf, cc);
410 }
411 } while (readfrom);
412 }
413
414 void
415 sendsig(signo)
416 char signo;
417 {
418 #ifdef KERBEROS
419 #ifdef CRYPT
420 if (doencrypt)
421 (void)des_write(rfd2, &signo, 1);
422 else
423 #endif
424 #endif
425 (void)write(rfd2, &signo, 1);
426 }
427
428 #ifdef KERBEROS
429 /* VARARGS */
430 warning(va_alist)
431 va_dcl
432 {
433 va_list ap;
434 char *fmt;
435
436 (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
437 va_start(ap);
438 fmt = va_arg(ap, char *);
439 vfprintf(stderr, fmt, ap);
440 va_end(ap);
441 (void)fprintf(stderr, ".\n");
442 }
443 #endif
444
445 char *
446 copyargs(argv)
447 char **argv;
448 {
449 register int cc;
450 register char **ap, *p;
451 char *args, *malloc();
452
453 cc = 0;
454 for (ap = argv; *ap; ++ap)
455 cc += strlen(*ap) + 1;
456 if (!(args = malloc((u_int)cc))) {
457 (void)fprintf(stderr, "rsh: %s.\n", strerror(ENOMEM));
458 exit(1);
459 }
460 for (p = args, ap = argv; *ap; ++ap) {
461 (void)strcpy(p, *ap);
462 for (p = strcpy(p, *ap); *p; ++p);
463 if (ap[1])
464 *p++ = ' ';
465 }
466 return(args);
467 }
468
469 usage()
470 {
471 (void)fprintf(stderr,
472 "usage: rsh [-nd%s]%s[-l login] host [command]\n",
473 #ifdef KERBEROS
474 #ifdef CRYPT
475 "x", " [-k realm] ");
476 #else
477 "", " [-k realm] ");
478 #endif
479 #else
480 "", " ");
481 #endif
482 exit(1);
483 }
484