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