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