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