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