]>
Commit | Line | Data |
---|---|---|
b7080c8e A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights | |
7 | * Reserved. This file contains Original Code and/or Modifications of | |
8 | * Original Code as defined in and that are subject to the Apple Public | |
9 | * Source License Version 1.0 (the 'License'). You may not use this file | |
10 | * except in compliance with the License. Please obtain a copy of the | |
11 | * License at http://www.apple.com/publicsource and read it before using | |
12 | * this file. | |
13 | * | |
14 | * The Original Code and all software distributed under the License are | |
15 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
19 | * License for the specific language governing rights and limitations | |
20 | * under the License." | |
21 | * | |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | /*- | |
25 | * Copyright (c) 1983, 1990, 1993, 1994 | |
26 | * The Regents of the University of California. All rights reserved. | |
27 | * | |
28 | * Redistribution and use in source and binary forms, with or without | |
29 | * modification, are permitted provided that the following conditions | |
30 | * are met: | |
31 | * 1. Redistributions of source code must retain the above copyright | |
32 | * notice, this list of conditions and the following disclaimer. | |
33 | * 2. Redistributions in binary form must reproduce the above copyright | |
34 | * notice, this list of conditions and the following disclaimer in the | |
35 | * documentation and/or other materials provided with the distribution. | |
36 | * 3. All advertising materials mentioning features or use of this software | |
37 | * must display the following acknowledgement: | |
38 | * This product includes software developed by the University of | |
39 | * California, Berkeley and its contributors. | |
40 | * 4. Neither the name of the University nor the names of its contributors | |
41 | * may be used to endorse or promote products derived from this software | |
42 | * without specific prior written permission. | |
43 | * | |
44 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
45 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
46 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
47 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
48 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
49 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
50 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
51 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
52 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
53 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
54 | * SUCH DAMAGE. | |
55 | */ | |
56 | ||
57 | ||
58 | /* | |
59 | * $Source: /cvs/Darwin/Commands/NeXT/network_cmds/rsh.tproj/rsh.c,v $ | |
60 | * $Header: /cvs/Darwin/Commands/NeXT/network_cmds/rsh.tproj/rsh.c,v 1.1.1.1 1999/05/02 03:58:17 wsanchez Exp $ | |
61 | */ | |
62 | ||
63 | #include <sys/types.h> | |
64 | #include <sys/signal.h> | |
65 | #include <sys/socket.h> | |
66 | #include <sys/ioctl.h> | |
67 | #include <sys/file.h> | |
68 | ||
69 | #include <netinet/in.h> | |
70 | #include <netdb.h> | |
71 | ||
72 | #include <err.h> | |
73 | #include <errno.h> | |
74 | #include <pwd.h> | |
75 | #include <signal.h> | |
76 | #include <stdio.h> | |
77 | #include <stdlib.h> | |
78 | #include <string.h> | |
79 | #include <unistd.h> | |
80 | #include <varargs.h> | |
81 | ||
82 | #include "pathnames.h" | |
83 | ||
84 | #ifdef KERBEROS | |
85 | #include <kerberosIV/des.h> | |
86 | #include <kerberosIV/krb.h> | |
87 | ||
88 | CREDENTIALS cred; | |
89 | Key_schedule schedule; | |
90 | int use_kerberos = 1, doencrypt; | |
91 | char dst_realm_buf[REALM_SZ], *dest_realm; | |
92 | extern char *krb_realmofhost(); | |
93 | #endif | |
94 | ||
95 | /* | |
96 | * rsh - remote shell | |
97 | */ | |
98 | int rfd2; | |
99 | ||
100 | char *copyargs __P((char **)); | |
101 | void sendsig __P((int)); | |
102 | void talk __P((int, long, pid_t, int)); | |
103 | void usage __P((void)); | |
104 | void warning __P(()); | |
105 | ||
106 | int | |
107 | main(argc, argv) | |
108 | int argc; | |
109 | char **argv; | |
110 | { | |
111 | struct passwd *pw; | |
112 | struct servent *sp; | |
113 | long omask; | |
114 | int argoff, asrsh, ch, dflag, nflag, one, rem; | |
115 | pid_t pid; | |
116 | uid_t uid; | |
117 | char *args, *host, *p, *user; | |
118 | ||
119 | argoff = asrsh = dflag = nflag = 0; | |
120 | one = 1; | |
121 | host = user = NULL; | |
122 | ||
123 | /* if called as something other than "rsh", use it as the host name */ | |
124 | if (p = strrchr(argv[0], '/')) | |
125 | ++p; | |
126 | else | |
127 | p = argv[0]; | |
128 | if (strcmp(p, "rsh")) | |
129 | host = p; | |
130 | else | |
131 | asrsh = 1; | |
132 | ||
133 | /* handle "rsh host flags" */ | |
134 | if (!host && argc > 2 && argv[1][0] != '-') { | |
135 | host = argv[1]; | |
136 | argoff = 1; | |
137 | } | |
138 | ||
139 | #ifdef KERBEROS | |
140 | #ifdef CRYPT | |
141 | #define OPTIONS "8KLdek:l:nwx" | |
142 | #else | |
143 | #define OPTIONS "8KLdek:l:nw" | |
144 | #endif | |
145 | #else | |
146 | #define OPTIONS "8KLdel:nw" | |
147 | #endif | |
148 | while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) | |
149 | switch(ch) { | |
150 | case 'K': | |
151 | #ifdef KERBEROS | |
152 | use_kerberos = 0; | |
153 | #endif | |
154 | break; | |
155 | case 'L': /* -8Lew are ignored to allow rlogin aliases */ | |
156 | case 'e': | |
157 | case 'w': | |
158 | case '8': | |
159 | break; | |
160 | case 'd': | |
161 | dflag = 1; | |
162 | break; | |
163 | case 'l': | |
164 | user = optarg; | |
165 | break; | |
166 | #ifdef KERBEROS | |
167 | case 'k': | |
168 | dest_realm = dst_realm_buf; | |
169 | strncpy(dest_realm, optarg, REALM_SZ); | |
170 | break; | |
171 | #endif | |
172 | case 'n': | |
173 | nflag = 1; | |
174 | break; | |
175 | #ifdef KERBEROS | |
176 | #ifdef CRYPT | |
177 | case 'x': | |
178 | doencrypt = 1; | |
179 | des_set_key(cred.session, schedule); | |
180 | break; | |
181 | #endif | |
182 | #endif | |
183 | case '?': | |
184 | default: | |
185 | usage(); | |
186 | } | |
187 | optind += argoff; | |
188 | ||
189 | /* if haven't gotten a host yet, do so */ | |
190 | if (!host && !(host = argv[optind++])) | |
191 | usage(); | |
192 | ||
193 | /* if no further arguments, must have been called as rlogin. */ | |
194 | if (!argv[optind]) { | |
195 | if (asrsh) | |
196 | *argv = "rlogin"; | |
197 | execv(_PATH_RLOGIN, argv); | |
198 | err(1, "can't exec %s", _PATH_RLOGIN); | |
199 | } | |
200 | ||
201 | argc -= optind; | |
202 | argv += optind; | |
203 | ||
204 | if (!(pw = getpwuid(uid = getuid()))) | |
205 | errx(1, "unknown user id"); | |
206 | /* Accept user1@host format, though "-l user2" overrides user1 */ | |
207 | p = strchr(host, '@'); | |
208 | if (p) { | |
209 | *p = '\0'; | |
210 | if (!user && p > host) | |
211 | user = host; | |
212 | host = p + 1; | |
213 | if (*host == '\0') | |
214 | usage(); | |
215 | } | |
216 | if (!user) | |
217 | user = pw->pw_name; | |
218 | ||
219 | #ifdef KERBEROS | |
220 | #ifdef CRYPT | |
221 | /* -x turns off -n */ | |
222 | if (doencrypt) | |
223 | nflag = 0; | |
224 | #endif | |
225 | #endif | |
226 | ||
227 | args = copyargs(argv); | |
228 | ||
229 | sp = NULL; | |
230 | #ifdef KERBEROS | |
231 | if (use_kerberos) { | |
232 | sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp"); | |
233 | if (sp == NULL) { | |
234 | use_kerberos = 0; | |
235 | warning("can't get entry for %s/tcp service", | |
236 | doencrypt ? "ekshell" : "kshell"); | |
237 | } | |
238 | } | |
239 | #endif | |
240 | if (sp == NULL) | |
241 | sp = getservbyname("shell", "tcp"); | |
242 | if (sp == NULL) | |
243 | errx(1, "shell/tcp: unknown service"); | |
244 | ||
245 | #ifdef KERBEROS | |
246 | try_connect: | |
247 | if (use_kerberos) { | |
248 | struct hostent *hp; | |
249 | ||
250 | /* fully qualify hostname (needed for krb_realmofhost) */ | |
251 | hp = gethostbyname(host); | |
252 | if (hp != NULL && !(host = strdup(hp->h_name))) | |
253 | err(1, NULL); | |
254 | ||
255 | rem = KSUCCESS; | |
256 | errno = 0; | |
257 | if (dest_realm == NULL) | |
258 | dest_realm = krb_realmofhost(host); | |
259 | ||
260 | #ifdef CRYPT | |
261 | if (doencrypt) | |
262 | rem = krcmd_mutual(&host, sp->s_port, user, args, | |
263 | &rfd2, dest_realm, &cred, schedule); | |
264 | else | |
265 | #endif | |
266 | rem = krcmd(&host, sp->s_port, user, args, &rfd2, | |
267 | dest_realm); | |
268 | if (rem < 0) { | |
269 | use_kerberos = 0; | |
270 | sp = getservbyname("shell", "tcp"); | |
271 | if (sp == NULL) | |
272 | errx(1, "shell/tcp: unknown service"); | |
273 | if (errno == ECONNREFUSED) | |
274 | warning("remote host doesn't support Kerberos"); | |
275 | if (errno == ENOENT) | |
276 | warning("can't provide Kerberos auth data"); | |
277 | goto try_connect; | |
278 | } | |
279 | } else { | |
280 | if (doencrypt) | |
281 | errx(1, "the -x flag requires Kerberos authentication"); | |
282 | rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2); | |
283 | } | |
284 | #else | |
285 | rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2); | |
286 | #endif | |
287 | ||
288 | if (rem < 0) | |
289 | exit(1); | |
290 | ||
291 | if (rfd2 < 0) | |
292 | errx(1, "can't establish stderr"); | |
293 | if (dflag) { | |
294 | if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, | |
295 | sizeof(one)) < 0) | |
296 | warn("setsockopt"); | |
297 | if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, | |
298 | sizeof(one)) < 0) | |
299 | warn("setsockopt"); | |
300 | } | |
301 | ||
302 | (void)setuid(uid); | |
303 | omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)); | |
304 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) | |
305 | (void)signal(SIGINT, sendsig); | |
306 | if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) | |
307 | (void)signal(SIGQUIT, sendsig); | |
308 | if (signal(SIGTERM, SIG_IGN) != SIG_IGN) | |
309 | (void)signal(SIGTERM, sendsig); | |
310 | ||
311 | if (!nflag) { | |
312 | pid = fork(); | |
313 | if (pid < 0) | |
314 | err(1, "fork"); | |
315 | } | |
316 | ||
317 | #ifdef KERBEROS | |
318 | #ifdef CRYPT | |
319 | if (!doencrypt) | |
320 | #endif | |
321 | #endif | |
322 | { | |
323 | (void)ioctl(rfd2, FIONBIO, &one); | |
324 | (void)ioctl(rem, FIONBIO, &one); | |
325 | } | |
326 | ||
327 | talk(nflag, omask, pid, rem); | |
328 | ||
329 | if (!nflag) | |
330 | (void)kill(pid, SIGKILL); | |
331 | exit(0); | |
332 | } | |
333 | ||
334 | void | |
335 | talk(nflag, omask, pid, rem) | |
336 | int nflag; | |
337 | long omask; | |
338 | pid_t pid; | |
339 | int rem; | |
340 | { | |
341 | int cc, wc; | |
342 | fd_set readfrom, ready, rembits; | |
343 | char *bp, buf[BUFSIZ]; | |
344 | ||
345 | if (!nflag && pid == 0) { | |
346 | (void)close(rfd2); | |
347 | ||
348 | reread: errno = 0; | |
349 | if ((cc = read(0, buf, sizeof buf)) <= 0) | |
350 | goto done; | |
351 | bp = buf; | |
352 | ||
353 | rewrite: | |
354 | FD_ZERO(&rembits); | |
355 | FD_SET(rem, &rembits); | |
356 | if (select(16, 0, &rembits, 0, 0) < 0) { | |
357 | if (errno != EINTR) | |
358 | err(1, "select"); | |
359 | goto rewrite; | |
360 | } | |
361 | if (!FD_ISSET(rem, &rembits)) | |
362 | goto rewrite; | |
363 | #ifdef KERBEROS | |
364 | #ifdef CRYPT | |
365 | if (doencrypt) | |
366 | wc = des_write(rem, bp, cc); | |
367 | else | |
368 | #endif | |
369 | #endif | |
370 | wc = write(rem, bp, cc); | |
371 | if (wc < 0) { | |
372 | if (errno == EWOULDBLOCK) | |
373 | goto rewrite; | |
374 | goto done; | |
375 | } | |
376 | bp += wc; | |
377 | cc -= wc; | |
378 | if (cc == 0) | |
379 | goto reread; | |
380 | goto rewrite; | |
381 | done: | |
382 | (void)shutdown(rem, 1); | |
383 | exit(0); | |
384 | } | |
385 | ||
386 | (void)sigsetmask(omask); | |
387 | FD_ZERO(&readfrom); | |
388 | FD_SET(rfd2, &readfrom); | |
389 | FD_SET(rem, &readfrom); | |
390 | do { | |
391 | ready = readfrom; | |
392 | if (select(16, &ready, 0, 0, 0) < 0) { | |
393 | if (errno != EINTR) | |
394 | err(1, "select"); | |
395 | continue; | |
396 | } | |
397 | if (FD_ISSET(rfd2, &ready)) { | |
398 | errno = 0; | |
399 | #ifdef KERBEROS | |
400 | #ifdef CRYPT | |
401 | if (doencrypt) | |
402 | cc = des_read(rfd2, buf, sizeof buf); | |
403 | else | |
404 | #endif | |
405 | #endif | |
406 | cc = read(rfd2, buf, sizeof buf); | |
407 | if (cc <= 0) { | |
408 | if (errno != EWOULDBLOCK) | |
409 | FD_CLR(rfd2, &readfrom); | |
410 | } else | |
411 | (void)write(2, buf, cc); | |
412 | } | |
413 | if (FD_ISSET(rem, &ready)) { | |
414 | errno = 0; | |
415 | #ifdef KERBEROS | |
416 | #ifdef CRYPT | |
417 | if (doencrypt) | |
418 | cc = des_read(rem, buf, sizeof buf); | |
419 | else | |
420 | #endif | |
421 | #endif | |
422 | cc = read(rem, buf, sizeof buf); | |
423 | if (cc <= 0) { | |
424 | if (errno != EWOULDBLOCK) | |
425 | FD_CLR(rem, &readfrom); | |
426 | } else | |
427 | (void)write(1, buf, cc); | |
428 | } | |
429 | } while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom)); | |
430 | } | |
431 | ||
432 | void | |
433 | sendsig(sig) | |
434 | int sig; | |
435 | { | |
436 | char signo; | |
437 | ||
438 | signo = sig; | |
439 | #ifdef KERBEROS | |
440 | #ifdef CRYPT | |
441 | if (doencrypt) | |
442 | (void)des_write(rfd2, &signo, 1); | |
443 | else | |
444 | #endif | |
445 | #endif | |
446 | (void)write(rfd2, &signo, 1); | |
447 | } | |
448 | ||
449 | #ifdef KERBEROS | |
450 | /* VARARGS */ | |
451 | void | |
452 | warning(va_alist) | |
453 | va_dcl | |
454 | { | |
455 | va_list ap; | |
456 | char *fmt; | |
457 | ||
458 | (void)fprintf(stderr, "rsh: warning, using standard rsh: "); | |
459 | va_start(ap); | |
460 | fmt = va_arg(ap, char *); | |
461 | vfprintf(stderr, fmt, ap); | |
462 | va_end(ap); | |
463 | (void)fprintf(stderr, ".\n"); | |
464 | } | |
465 | #endif | |
466 | ||
467 | char * | |
468 | copyargs(argv) | |
469 | char **argv; | |
470 | { | |
471 | int cc; | |
472 | char **ap, *args, *p; | |
473 | ||
474 | cc = 0; | |
475 | for (ap = argv; *ap; ++ap) | |
476 | cc += strlen(*ap) + 1; | |
477 | if (!(args = malloc((u_int)cc))) | |
478 | err(1, NULL); | |
479 | for (p = args, ap = argv; *ap; ++ap) { | |
480 | (void)strcpy(p, *ap); | |
481 | for (p = strcpy(p, *ap); *p; ++p); | |
482 | if (ap[1]) | |
483 | *p++ = ' '; | |
484 | } | |
485 | return (args); | |
486 | } | |
487 | ||
488 | void | |
489 | usage() | |
490 | { | |
491 | ||
492 | (void)fprintf(stderr, | |
493 | "usage: rsh [-nd%s]%s[-l login] [login@]host [command]\n", | |
494 | #ifdef KERBEROS | |
495 | #ifdef CRYPT | |
496 | "x", " [-k realm] "); | |
497 | #else | |
498 | "", " [-k realm] "); | |
499 | #endif | |
500 | #else | |
501 | "", " "); | |
502 | #endif | |
503 | exit(1); | |
504 | } |