1 #ifndef lint 2 static char sccsid[] = "@(#)rlogin.c 4.17 (Berkeley) 85/03/17"; 3 #endif 4 5 /* 6 * rlogin - remote login 7 */ 8 #include <sys/types.h> 9 #include <sys/socket.h> 10 #include <sys/wait.h> 11 12 #include <netinet/in.h> 13 14 #include <stdio.h> 15 #include <sgtty.h> 16 #include <errno.h> 17 #include <pwd.h> 18 #include <signal.h> 19 #include <netdb.h> 20 #include <setjmp.h> 21 22 char *index(), *rindex(), *malloc(), *getenv(); 23 struct passwd *getpwuid(); 24 char *name; 25 int rem; 26 char cmdchar = '~'; 27 int eight; 28 char *speeds[] = 29 { "0", "50", "75", "110", "134", "150", "200", "300", 30 "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 31 char term[256] = "network"; 32 extern int errno; 33 int lostpeer(); 34 int nosigwin; 35 jmp_buf winsizechanged; 36 struct winsize winsize; 37 int sigwinch(); 38 39 main(argc, argv) 40 int argc; 41 char **argv; 42 { 43 char *host, *cp; 44 struct sgttyb ttyb; 45 struct passwd *pwd; 46 struct servent *sp; 47 int uid, options = 0; 48 int on = 1; 49 50 host = rindex(argv[0], '/'); 51 if (host) 52 host++; 53 else 54 host = argv[0]; 55 argv++, --argc; 56 if (!strcmp(host, "rlogin")) 57 host = *argv++, --argc; 58 another: 59 if (argc > 0 && !strcmp(*argv, "-d")) { 60 argv++, argc--; 61 options |= SO_DEBUG; 62 goto another; 63 } 64 if (argc > 0 && !strcmp(*argv, "-l")) { 65 argv++, argc--; 66 if (argc == 0) 67 goto usage; 68 name = *argv++; argc--; 69 goto another; 70 } 71 if (argc > 0 && !strncmp(*argv, "-e", 2)) { 72 cmdchar = argv[0][2]; 73 argv++, argc--; 74 goto another; 75 } 76 if (argc > 0 && !strcmp(*argv, "-8")) { 77 eight = 1; 78 argv++, argc--; 79 goto another; 80 } 81 if (argc > 0 && !strcmp(*argv, "-w")) { 82 nosigwin++; 83 argv++, argc--; 84 goto another; 85 } 86 if (host == 0) 87 goto usage; 88 if (argc > 0) 89 goto usage; 90 pwd = getpwuid(getuid()); 91 if (pwd == 0) { 92 fprintf(stderr, "Who are you?\n"); 93 exit(1); 94 } 95 sp = getservbyname("login", "tcp"); 96 if (sp == 0) { 97 fprintf(stderr, "rlogin: login/tcp: unknown service\n"); 98 exit(2); 99 } 100 cp = getenv("TERM"); 101 if (cp) 102 strcpy(term, cp); 103 if (ioctl(0, TIOCGETP, &ttyb) == 0) { 104 strcat(term, "/"); 105 strcat(term, speeds[ttyb.sg_ospeed]); 106 } 107 if (!nosigwin && ioctl(0, TIOCGWINSZ, &winsize) == 0) { 108 cp = index(term, '\0'); 109 sprintf(cp, "/%u,%u,%u,%u", winsize.ws_row, winsize.ws_col, 110 winsize.ws_xpixel, winsize.ws_ypixel); 111 } 112 signal(SIGPIPE, lostpeer); 113 rem = rcmd(&host, sp->s_port, pwd->pw_name, 114 name ? name : pwd->pw_name, term, 0); 115 if (rem < 0) 116 exit(1); 117 if (options & SO_DEBUG && 118 setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) 119 perror("rlogin: setsockopt (SO_DEBUG)"); 120 uid = getuid(); 121 if (setuid(uid) < 0) { 122 perror("rlogin: setuid"); 123 exit(1); 124 } 125 doit(); 126 /*NOTREACHED*/ 127 usage: 128 fprintf(stderr, 129 "usage: rlogin host [ -ex ] [ -l username ] [ -8 ]\n"); 130 exit(1); 131 } 132 133 #define CRLF "\r\n" 134 135 int child; 136 int catchild(); 137 138 int defflags, tabflag; 139 char deferase, defkill; 140 struct tchars deftc; 141 struct ltchars defltc; 142 struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 143 struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 144 145 doit() 146 { 147 int exit(); 148 struct sgttyb sb; 149 150 ioctl(0, TIOCGETP, (char *)&sb); 151 defflags = sb.sg_flags; 152 tabflag = defflags & TBDELAY; 153 defflags &= ECHO | CRMOD; 154 deferase = sb.sg_erase; 155 defkill = sb.sg_kill; 156 ioctl(0, TIOCGETC, (char *)&deftc); 157 notc.t_startc = deftc.t_startc; 158 notc.t_stopc = deftc.t_stopc; 159 ioctl(0, TIOCGLTC, (char *)&defltc); 160 signal(SIGINT, exit); 161 signal(SIGHUP, exit); 162 signal(SIGQUIT, exit); 163 child = fork(); 164 if (child == -1) { 165 perror("rlogin: fork"); 166 done(); 167 } 168 signal(SIGINT, SIG_IGN); 169 mode(1); 170 if (child == 0) { 171 reader(); 172 sleep(1); 173 prf("\007Connection closed."); 174 exit(3); 175 } 176 signal(SIGCHLD, catchild); 177 if (!nosigwin) 178 signal(SIGWINCH, sigwinch); 179 writer(); 180 prf("Closed connection."); 181 done(); 182 } 183 184 done() 185 { 186 187 mode(0); 188 if (child > 0 && kill(child, SIGKILL) >= 0) 189 wait((int *)0); 190 exit(0); 191 } 192 193 catchild() 194 { 195 union wait status; 196 int pid; 197 198 again: 199 pid = wait3(&status, WNOHANG|WUNTRACED, 0); 200 if (pid == 0) 201 return; 202 /* 203 * if the child (reader) dies, just quit 204 */ 205 if (pid < 0 || pid == child && !WIFSTOPPED(status)) 206 done(); 207 goto again; 208 } 209 210 /* 211 * writer: write to remote: 0 -> line. 212 * ~. terminate 213 * ~^Z suspend rlogin process. 214 * ~^Y suspend rlogin process, but leave reader alone. 215 */ 216 writer() 217 { 218 char obuf[600], c; 219 register char *op; 220 register n; 221 222 /* 223 * Handle SIGWINCH's with in-band signaling of new 224 * window size. It seems reasonable that we flush 225 * pending input and not force out of band signal 226 * as this most likely will occur from an input device 227 * other than the keyboard (e.g. a mouse). 228 * 229 * The hack of using 0377 to signal an in-band signal 230 * is pretty bad, but otherwise we'd be forced to 231 * either get complicated (use MSG_OOB) or go to a 232 * serious (telnet-style) protocol. 233 */ 234 if (setjmp(winsizechanged)) { 235 struct winsize *wp = (struct winsize *)(obuf+4); 236 237 obuf[0] = 0377; /* XXX */ 238 obuf[1] = 0377; /* XXX */ 239 obuf[2] = 's'; /* XXX */ 240 obuf[3] = 's'; /* XXX */ 241 wp->ws_row = htons(winsize.ws_row); 242 wp->ws_col = htons(winsize.ws_col); 243 wp->ws_xpixel = htons(winsize.ws_xpixel); 244 wp->ws_ypixel = htons(winsize.ws_ypixel); 245 (void) write(rem, obuf, 4+sizeof (*wp)); 246 } 247 top: 248 op = obuf; 249 for (;;) { 250 int local; 251 252 n = read(0, &c, 1); 253 if (n <= 0) { 254 if (n < 0 && errno == EINTR) 255 continue; 256 break; 257 } 258 if (!eight) 259 c &= 0177; 260 /* 261 * If we're at the beginning of the line 262 * and recognize a command character, then 263 * we echo locally. Otherwise, characters 264 * are echo'd remotely. If the command 265 * character is doubled, this acts as a 266 * force and local echo is suppressed. 267 */ 268 if (op == obuf) 269 local = (c == cmdchar); 270 if (op == obuf + 1 && *obuf == cmdchar) 271 local = (c != cmdchar); 272 if (!local) { 273 if (write(rem, &c, 1) == 0) { 274 prf("line gone"); 275 return; 276 } 277 if (!eight) 278 c &= 0177; 279 } else { 280 if (c == '\r' || c == '\n') { 281 char cmdc = obuf[1]; 282 283 if (cmdc == '.' || cmdc == deftc.t_eofc) { 284 write(0, CRLF, sizeof(CRLF)); 285 return; 286 } 287 if (cmdc == defltc.t_suspc || 288 cmdc == defltc.t_dsuspc) { 289 stop(cmdc); 290 goto top; 291 } 292 *op++ = c; 293 write(rem, obuf, op - obuf); 294 goto top; 295 } 296 write(1, &c, 1); 297 } 298 *op++ = c; 299 if (c == deferase) { 300 op -= 2; 301 if (op < obuf) 302 goto top; 303 } 304 if (c == defkill || c == deftc.t_eofc || 305 c == '\r' || c == '\n') 306 goto top; 307 if (op >= &obuf[sizeof (obuf)]) 308 op--; 309 } 310 } 311 312 stop(cmdc) 313 char cmdc; 314 { 315 struct winsize ws; 316 317 write(0, CRLF, sizeof(CRLF)); 318 mode(0); 319 signal(SIGCHLD, SIG_IGN); 320 kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); 321 signal(SIGCHLD, catchild); 322 mode(1); 323 sigwinch(); /* check for size changes */ 324 } 325 326 sigwinch() 327 { 328 struct winsize ws; 329 330 if (!nosigwin && ioctl(0, TIOCGWINSZ, &ws) == 0 && 331 bcmp(&ws, &winsize, sizeof (ws))) { 332 winsize = ws; 333 longjmp(winsizechanged, 1); 334 } 335 } 336 337 oob() 338 { 339 int out = 1+1, atmark; 340 char waste[BUFSIZ], mark; 341 342 ioctl(1, TIOCFLUSH, (char *)&out); 343 for (;;) { 344 if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 345 perror("ioctl"); 346 break; 347 } 348 if (atmark) 349 break; 350 (void) read(rem, waste, sizeof (waste)); 351 } 352 recv(rem, &mark, 1, MSG_OOB); 353 if (mark & TIOCPKT_NOSTOP) { 354 notc.t_stopc = -1; 355 notc.t_startc = -1; 356 ioctl(0, TIOCSETC, (char *)¬c); 357 } 358 if (mark & TIOCPKT_DOSTOP) { 359 notc.t_stopc = deftc.t_stopc; 360 notc.t_startc = deftc.t_startc; 361 ioctl(0, TIOCSETC, (char *)¬c); 362 } 363 } 364 365 /* 366 * reader: read from remote: line -> 1 367 */ 368 reader() 369 { 370 char rb[BUFSIZ]; 371 register int cnt; 372 373 signal(SIGURG, oob); 374 { int pid = -getpid(); 375 ioctl(rem, SIOCSPGRP, (char *)&pid); } 376 for (;;) { 377 cnt = read(rem, rb, sizeof (rb)); 378 if (cnt == 0) 379 break; 380 if (cnt < 0) { 381 if (errno == EINTR) 382 continue; 383 break; 384 } 385 write(1, rb, cnt); 386 } 387 } 388 389 mode(f) 390 { 391 struct tchars *tc; 392 struct ltchars *ltc; 393 struct sgttyb sb; 394 395 ioctl(0, TIOCGETP, (char *)&sb); 396 switch (f) { 397 398 case 0: 399 sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 400 sb.sg_flags |= defflags|tabflag; 401 tc = &deftc; 402 ltc = &defltc; 403 sb.sg_kill = defkill; 404 sb.sg_erase = deferase; 405 break; 406 407 case 1: 408 sb.sg_flags |= (eight ? RAW : CBREAK); 409 sb.sg_flags &= ~defflags; 410 /* preserve tab delays, but turn off XTABS */ 411 if ((sb.sg_flags & TBDELAY) == XTABS) 412 sb.sg_flags &= ~TBDELAY; 413 tc = ¬c; 414 ltc = &noltc; 415 sb.sg_kill = sb.sg_erase = -1; 416 break; 417 418 default: 419 return; 420 } 421 ioctl(0, TIOCSLTC, (char *)ltc); 422 ioctl(0, TIOCSETC, (char *)tc); 423 ioctl(0, TIOCSETN, (char *)&sb); 424 } 425 426 /*VARARGS*/ 427 prf(f, a1, a2, a3) 428 char *f; 429 { 430 fprintf(stderr, f, a1, a2, a3); 431 fprintf(stderr, CRLF); 432 } 433 434 lostpeer() 435 { 436 signal(SIGPIPE, SIG_IGN); 437 prf("\007Connection closed."); 438 done(); 439 } 440