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