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