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