1 /* 2 * Copyright (c) 1983 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)rsh.c 5.7 (Berkeley) 9/20/88"; 26 #endif /* not lint */ 27 28 #include <sys/types.h> 29 #include <sys/socket.h> 30 #include <sys/ioctl.h> 31 #include <sys/file.h> 32 33 #include <netinet/in.h> 34 35 #include <stdio.h> 36 #include <errno.h> 37 #include <signal.h> 38 #include <pwd.h> 39 #include <netdb.h> 40 41 #ifdef KERBEROS 42 #include <kerberos/krb.h> 43 char krb_realm[REALM_SZ]; 44 int use_kerberos = 1, encrypt = 0; 45 CREDENTIALS cred; 46 Key_schedule schedule; 47 #endif /* KERBEROS */ 48 49 /* 50 * rsh - remote shell 51 */ 52 /* VARARGS */ 53 int error(); 54 char *index(), *rindex(), *malloc(), *getpass(), *strcpy(); 55 56 struct passwd *getpwuid(); 57 58 int errno; 59 int options; 60 int rfd2; 61 int nflag; 62 int sendsig(); 63 64 #define mask(s) (1 << ((s) - 1)) 65 66 main(argc, argv0) 67 int argc; 68 char **argv0; 69 { 70 int rem, pid; 71 char *host, *cp, **ap, buf[BUFSIZ], *args, **argv = argv0, *user = 0; 72 register int cc; 73 int asrsh = 0; 74 struct passwd *pwd; 75 int readfrom, ready; 76 int one = 1; 77 struct servent *sp; 78 int omask; 79 80 host = rindex(argv[0], '/'); 81 if (host) 82 host++; 83 else 84 host = argv[0]; 85 argv++, --argc; 86 if (!strcmp(host, "rsh")) { 87 host = *argv++, --argc; 88 asrsh = 1; 89 } 90 another: 91 if (argc > 0 && !strcmp(*argv, "-l")) { 92 argv++, argc--; 93 if (argc > 0) 94 user = *argv++, argc--; 95 goto another; 96 } 97 if (argc > 0 && !strcmp(*argv, "-n")) { 98 argv++, argc--; 99 nflag++; 100 goto another; 101 } 102 if (argc > 0 && !strcmp(*argv, "-d")) { 103 argv++, argc--; 104 options |= SO_DEBUG; 105 goto another; 106 } 107 /* 108 * Ignore the -L, -w, -e and -8 flags to allow aliases with rlogin 109 * to work 110 * 111 * There must be a better way to do this! -jmb 112 */ 113 if (argc > 0 && !strncmp(*argv, "-L", 2)) { 114 argv++, argc--; 115 goto another; 116 } 117 if (argc > 0 && !strncmp(*argv, "-w", 2)) { 118 argv++, argc--; 119 goto another; 120 } 121 if (argc > 0 && !strncmp(*argv, "-e", 2)) { 122 argv++, argc--; 123 goto another; 124 } 125 if (argc > 0 && !strncmp(*argv, "-8", 2)) { 126 argv++, argc--; 127 goto another; 128 } 129 130 #ifdef KERBEROS 131 if(argc > 0 && !strncmp(*argv, "-x", 2)) { 132 encrypt = 1; 133 des_set_key(cred.session, schedule); 134 argv++, argc--; 135 goto another; 136 } 137 138 if(argc > 0 && !strcmp(*argv, "-k")) { 139 argv++, argc--; 140 if(argc <= 0 || (**argv == '-')) { 141 fprintf(stderr, "-k option requires an argument\n"); 142 exit(1); 143 } 144 strncpy(krb_realm, *argv, REALM_SZ); 145 argv++, argc--; 146 goto another; 147 } 148 #endif 149 150 if (host == 0) 151 goto usage; 152 if (argv[0] == 0) { 153 if (asrsh) 154 *argv0 = "rlogin"; 155 execv("/usr/ucb/rlogin", argv0); 156 perror("/usr/ucb/rlogin"); 157 exit(1); 158 } 159 pwd = getpwuid(getuid()); 160 if (pwd == 0) { 161 fprintf(stderr, "who are you?\n"); 162 exit(1); 163 } 164 cc = 0; 165 for (ap = argv; *ap; ap++) 166 cc += strlen(*ap) + 1; 167 cp = args = malloc(cc); 168 for (ap = argv; *ap; ap++) { 169 (void) strcpy(cp, *ap); 170 while (*cp) 171 cp++; 172 if (ap[1]) 173 *cp++ = ' '; 174 } 175 #ifdef KERBEROS 176 sp = getservbyname("kshell", "tcp"); 177 if (sp == NULL) { 178 use_kerberos = 0; 179 old_warning("kshell service unknown"); 180 sp = getservbyname("shell", "tcp"); 181 } 182 #else 183 sp = getservbyname("shell", "tcp"); 184 #endif 185 186 if (sp == 0) { 187 fprintf(stderr, "rsh: shell/tcp: unknown service\n"); 188 exit(1); 189 } 190 191 #ifdef KERBEROS 192 try_connect: 193 if(use_kerberos) { 194 rem = KSUCCESS; 195 if(krb_realm[0] == '\0') { 196 rem = krb_get_lrealm(krb_realm, 1); 197 } 198 199 if(rem == KSUCCESS) { 200 if(encrypt) { 201 rem = krcmd_mutual( 202 &host, sp->s_port, 203 user ? user : pwd->pw_name, 204 args, 205 &rfd2, 206 krb_realm, 207 &cred, schedule); 208 } else { 209 rem = krcmd( 210 &host, 211 sp->s_port, 212 user ? user : pwd->pw_name, 213 args, 214 &rfd2, 215 krb_realm 216 ); 217 } 218 } else { 219 fprintf(stderr, 220 "%s: error getting local realm\n", 221 argv0[0]); 222 exit(1); 223 } 224 if((rem < 0) && errno == ECONNREFUSED) { 225 use_kerberos = 0; 226 sp = getservbyname("shell", "tcp"); 227 if(sp == NULL) { 228 fprintf(stderr, "unknown service shell/tcp\n"); 229 exit(1); 230 } 231 old_warning("remote host doesn't support Kerberos"); 232 goto try_connect; 233 } 234 } else { 235 if(encrypt) { 236 fprintf(stderr,"The -x flag requires Kerberos authentication\n"); 237 exit(1); 238 } 239 rem = rcmd(&host, sp->s_port, pwd->pw_name, 240 user ? user : pwd->pw_name, args, &rfd2); 241 } 242 243 #else 244 245 rem = rcmd(&host, sp->s_port, pwd->pw_name, 246 user ? user : pwd->pw_name, args, &rfd2); 247 #endif 248 249 if (rem < 0) 250 exit(1); 251 252 if (rfd2 < 0) { 253 fprintf(stderr, "rsh: can't establish stderr\n"); 254 exit(2); 255 } 256 if (options & SO_DEBUG) { 257 if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof (one)) < 0) 258 perror("setsockopt (stdin)"); 259 if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, sizeof (one)) < 0) 260 perror("setsockopt (stderr)"); 261 } 262 (void) setuid(getuid()); 263 omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM)); 264 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 265 signal(SIGINT, sendsig); 266 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 267 signal(SIGQUIT, sendsig); 268 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 269 signal(SIGTERM, sendsig); 270 if (nflag == 0) { 271 pid = fork(); 272 if (pid < 0) { 273 perror("fork"); 274 exit(1); 275 } 276 } 277 ioctl(rfd2, FIONBIO, &one); 278 ioctl(rem, FIONBIO, &one); 279 if (nflag == 0 && pid == 0) { 280 char *bp; int rembits, wc; 281 (void) close(rfd2); 282 reread: 283 errno = 0; 284 cc = read(0, buf, sizeof buf); 285 if (cc <= 0) 286 goto done; 287 bp = buf; 288 rewrite: 289 rembits = 1<<rem; 290 if (select(16, 0, &rembits, 0, 0) < 0) { 291 if (errno != EINTR) { 292 perror("select"); 293 exit(1); 294 } 295 goto rewrite; 296 } 297 if ((rembits & (1<<rem)) == 0) 298 goto rewrite; 299 wc = write(rem, bp, cc); 300 if (wc < 0) { 301 if (errno == EWOULDBLOCK) 302 goto rewrite; 303 goto done; 304 } 305 cc -= wc; bp += wc; 306 if (cc == 0) 307 goto reread; 308 goto rewrite; 309 done: 310 (void) shutdown(rem, 1); 311 exit(0); 312 } 313 sigsetmask(omask); 314 readfrom = (1<<rfd2) | (1<<rem); 315 do { 316 ready = readfrom; 317 if (select(16, &ready, 0, 0, 0) < 0) { 318 if (errno != EINTR) { 319 perror("select"); 320 exit(1); 321 } 322 continue; 323 } 324 if (ready & (1<<rfd2)) { 325 errno = 0; 326 cc = read(rfd2, buf, sizeof buf); 327 if (cc <= 0) { 328 if (errno != EWOULDBLOCK) 329 readfrom &= ~(1<<rfd2); 330 } else 331 (void) write(2, buf, cc); 332 } 333 if (ready & (1<<rem)) { 334 errno = 0; 335 cc = read(rem, buf, sizeof buf); 336 if (cc <= 0) { 337 if (errno != EWOULDBLOCK) 338 readfrom &= ~(1<<rem); 339 } else 340 (void) write(1, buf, cc); 341 } 342 } while (readfrom); 343 if (nflag == 0) 344 (void) kill(pid, SIGKILL); 345 exit(0); 346 usage: 347 fprintf(stderr, 348 #ifdef KERBEROS 349 "usage: rsh host [ -l login ] [ -n ] [ -k realm ] command\n"); 350 #else 351 "usage: rsh host [ -l login ] [ -n ] command\n"); 352 #endif 353 exit(1); 354 } 355 356 sendsig(signo) 357 char signo; 358 { 359 360 (void) write(rfd2, &signo, 1); 361 } 362 363 #ifdef KERBEROS 364 int 365 old_warning(str) 366 char *str; 367 { 368 fprintf(stderr,"Warning: %s, using standard rsh\n", str); 369 } 370 #endif 371