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