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