BSD 4_3_Reno release
[unix-history] / usr / src / usr.bin / rsh / rsh.c
CommitLineData
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
21char 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 27static 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
55CREDENTIALS cred;
56Key_schedule schedule;
57int use_kerberos = 1, encrypt;
58char dst_realm_buf[REALM_SZ], *dest_realm;
59extern char *krb_realmofhost();
60#endif
d70fc2d1 61
4a31bc6f
BJ
62/*
63 * rsh - remote shell
64 */
c2ef0242
KB
65extern int errno;
66int rfd2;
4ca10280 67
c2ef0242 68main(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 196try_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
286talk(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
299reread: errno = 0;
300 if ((cc = read(0, buf, sizeof buf)) <= 0)
4a31bc6f
BJ
301 goto done;
302 bp = buf;
c2ef0242
KB
303
304rewrite: 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
331done:
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 379void
4a31bc6f 380sendsig(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 */
393warning(va_alist)
394va_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
408char *
409copyargs(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
432usage()
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}