POSIX 1003.2B/D9 symbolic links
[unix-history] / usr / src / usr.bin / rsh / rsh.c
CommitLineData
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
9static 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 15static 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
43CREDENTIALS cred;
44Key_schedule schedule;
19188d44 45int use_kerberos = 1, doencrypt;
c2ef0242
KB
46char dst_realm_buf[REALM_SZ], *dest_realm;
47extern char *krb_realmofhost();
48#endif
d70fc2d1 49
4a31bc6f
BJ
50/*
51 * rsh - remote shell
52 */
c2ef0242
KB
53extern int errno;
54int rfd2;
4ca10280 55
c2ef0242 56main(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 178try_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
270talk(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
283reread: errno = 0;
284 if ((cc = read(0, buf, sizeof buf)) <= 0)
4a31bc6f
BJ
285 goto done;
286 bp = buf;
c2ef0242
KB
287
288rewrite: 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
312done:
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 354void
4a31bc6f 355sendsig(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 */
365warning(va_alist)
366va_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
380char *
381copyargs(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
404usage()
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}