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