1 /* 2 * Copyright (c) 1983, 1988 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, 1988 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[] = "@(#)rlogind.c 5.22.1.8 (Berkeley) 10/02/89"; 26 #endif /* not lint */ 27 28 /* 29 * remote login server: 30 * \0 31 * remuser\0 32 * locuser\0 33 * terminal_type/speed\0 34 * data 35 * 36 * Automatic login protocol is done here, using login -f upon success, 37 * unless OLD_LOGIN is defined (then done in login, ala 4.2/4.3BSD). 38 */ 39 40 #include <stdio.h> 41 #include <sys/param.h> 42 #include <sys/stat.h> 43 #include <sys/socket.h> 44 #include <sys/wait.h> 45 #include <sys/file.h> 46 #include <sys/ioctl.h> 47 #if BSD > 43 48 #include <sys/termios.h> 49 #endif 50 51 #include <netinet/in.h> 52 53 #include <errno.h> 54 #include <pwd.h> 55 #include <signal.h> 56 #include <stdio.h> 57 #include <netdb.h> 58 #include <syslog.h> 59 #include <strings.h> 60 61 #ifndef TIOCPKT_WINDOW 62 #define TIOCPKT_WINDOW 0x80 63 #endif 64 65 char *env[2]; 66 #define NMAX 30 67 char lusername[NMAX+1], rusername[NMAX+1]; 68 static char term[64] = "TERM="; 69 #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 70 int keepalive = 1; 71 int check_all = 0; 72 73 #define SUPERUSER(pwd) ((pwd)->pw_uid == 0) 74 75 extern int errno; 76 int reapchild(); 77 struct passwd *getpwnam(), *pwd; 78 char *malloc(); 79 80 main(argc, argv) 81 int argc; 82 char **argv; 83 { 84 extern int opterr, optind, _check_rhosts_file; 85 int ch; 86 int on = 1, fromlen; 87 struct sockaddr_in from; 88 89 openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 90 91 opterr = 0; 92 while ((ch = getopt(argc, argv, "aln")) != EOF) 93 switch (ch) { 94 case 'a': 95 check_all = 1; 96 break; 97 case 'l': 98 _check_rhosts_file = 0; 99 break; 100 case 'n': 101 keepalive = 0; 102 break; 103 case '?': 104 default: 105 syslog(LOG_ERR, "usage: rlogind [-a] [-l] [-n]"); 106 break; 107 } 108 argc -= optind; 109 argv += optind; 110 111 fromlen = sizeof (from); 112 if (getpeername(0, &from, &fromlen) < 0) { 113 syslog(LOG_ERR, "Couldn't get peer name of remote host: %m"); 114 fatalperror("Can't get peer name of remote host"); 115 } 116 if (keepalive && 117 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 118 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 119 doit(0, &from); 120 } 121 122 int child; 123 int cleanup(); 124 int netf; 125 char *line; 126 extern char *inet_ntoa(); 127 128 struct winsize win = { 0, 0, 0, 0 }; 129 130 131 doit(f, fromp) 132 int f; 133 struct sockaddr_in *fromp; 134 { 135 int i, p, t, pid, on = 1; 136 #ifndef OLD_LOGIN 137 int authenticated = 0, hostok = 0; 138 char remotehost[2 * MAXHOSTNAMELEN + 1]; 139 #endif 140 register struct hostent *hp; 141 struct hostent hostent; 142 char c; 143 144 alarm(60); 145 read(f, &c, 1); 146 if (c != 0) 147 exit(1); 148 149 alarm(0); 150 fromp->sin_port = ntohs((u_short)fromp->sin_port); 151 hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 152 fromp->sin_family); 153 if (hp == 0) { 154 /* 155 * Only the name is used below. 156 */ 157 hp = &hostent; 158 hp->h_name = inet_ntoa(fromp->sin_addr); 159 #ifndef OLD_LOGIN 160 hostok++; 161 #endif 162 } 163 #ifndef OLD_LOGIN 164 else if (check_all || local_domain(hp->h_name)) { 165 /* 166 * If name returned by gethostbyaddr is in our domain, 167 * attempt to verify that we haven't been fooled by someone 168 * in a remote net; look up the name and check that this 169 * address corresponds to the name. 170 */ 171 strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 172 remotehost[sizeof(remotehost) - 1] = 0; 173 hp = gethostbyname(remotehost); 174 if (hp) 175 #ifdef h_addr /* 4.2 hack */ 176 for (; hp->h_addr_list[0]; hp->h_addr_list++) 177 if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 178 sizeof(fromp->sin_addr))) { 179 hostok++; 180 break; 181 } 182 #else 183 if (!bcmp(hp->h_addr, (caddr_t)&fromp->sin_addr, 184 sizeof(fromp->sin_addr))) 185 hostok++; 186 #endif 187 } else 188 hostok++; 189 #endif /* OLD_LOGIN */ 190 191 if (fromp->sin_family != AF_INET || 192 fromp->sin_port >= IPPORT_RESERVED || 193 fromp->sin_port < IPPORT_RESERVED/2) { 194 syslog(LOG_NOTICE, "Connection from %s on illegal port", 195 inet_ntoa(fromp->sin_addr)); 196 fatal(f, "Permission denied"); 197 } 198 #ifdef IP_OPTIONS 199 { 200 u_char optbuf[BUFSIZ/3], *cp; 201 char lbuf[BUFSIZ], *lp; 202 int optsize = sizeof(optbuf), ipproto; 203 struct protoent *ip; 204 205 if ((ip = getprotobyname("ip")) != NULL) 206 ipproto = ip->p_proto; 207 else 208 ipproto = IPPROTO_IP; 209 if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) == 0 && 210 optsize != 0) { 211 lp = lbuf; 212 for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 213 sprintf(lp, " %2.2x", *cp); 214 syslog(LOG_NOTICE, 215 "Connection received using IP options (ignored):%s", lbuf); 216 if (setsockopt(0, ipproto, IP_OPTIONS, 217 (char *)NULL, &optsize) != 0) { 218 syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 219 exit(1); 220 } 221 } 222 } 223 #endif 224 write(f, "", 1); 225 #ifndef OLD_LOGIN 226 if (do_rlogin(hp->h_name) == 0) { 227 if (hostok) 228 authenticated++; 229 else 230 write(f, "rlogind: Host address mismatch.\r\n", 231 sizeof("rlogind: Host address mismatch.\r\n") - 1); 232 } 233 #endif 234 235 for (c = 'p'; c <= 's'; c++) { 236 struct stat stb; 237 line = "/dev/ptyXX"; 238 line[strlen("/dev/pty")] = c; 239 line[strlen("/dev/ptyp")] = '0'; 240 if (stat(line, &stb) < 0) 241 break; 242 for (i = 0; i < 16; i++) { 243 line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 244 p = open(line, O_RDWR); 245 if (p > 0) 246 goto gotpty; 247 } 248 } 249 fatal(f, "Out of ptys"); 250 /*NOTREACHED*/ 251 gotpty: 252 (void) ioctl(p, TIOCSWINSZ, &win); 253 netf = f; 254 line[strlen("/dev/")] = 't'; 255 t = open(line, O_RDWR); 256 if (t < 0) 257 fatalperror(f, line); 258 if (fchmod(t, 0)) 259 fatalperror(f, line); 260 (void)signal(SIGHUP, SIG_IGN); 261 vhangup(); 262 (void)signal(SIGHUP, SIG_DFL); 263 t = open(line, O_RDWR); 264 if (t < 0) 265 fatalperror(f, line); 266 setup_term(t); 267 #ifdef DEBUG 268 { 269 int tt = open("/dev/tty", O_RDWR); 270 if (tt > 0) { 271 (void)ioctl(tt, TIOCNOTTY, 0); 272 (void)close(tt); 273 } 274 } 275 #endif 276 pid = fork(); 277 if (pid < 0) 278 fatalperror(f, ""); 279 if (pid == 0) { 280 #if BSD > 43 281 if (setsid() < 0) 282 fatalperror(f, "setsid"); 283 if (ioctl(t, TIOCSCTTY, 0) < 0) 284 fatalperror(f, "ioctl(sctty)"); 285 #endif 286 close(f), close(p); 287 dup2(t, 0), dup2(t, 1), dup2(t, 2); 288 close(t); 289 #ifdef OLD_LOGIN 290 execl("/bin/login", "login", "-r", hp->h_name, 0); 291 #else /* OLD_LOGIN */ 292 if (authenticated) 293 execl("/bin/login", "login", "-p", "-h", hp->h_name, 294 "-f", lusername, 0); 295 else 296 execl("/bin/login", "login", "-p", "-h", hp->h_name, 297 lusername, 0); 298 #endif /* OLD_LOGIN */ 299 fatalperror(2, "/bin/login"); 300 /*NOTREACHED*/ 301 } 302 close(t); 303 304 ioctl(f, FIONBIO, &on); 305 ioctl(p, FIONBIO, &on); 306 ioctl(p, TIOCPKT, &on); 307 signal(SIGTSTP, SIG_IGN); 308 signal(SIGCHLD, cleanup); 309 setpgrp(0, 0); 310 protocol(f, p); 311 signal(SIGCHLD, SIG_IGN); 312 cleanup(); 313 } 314 315 char magic[2] = { 0377, 0377 }; 316 char oobdata[] = {TIOCPKT_WINDOW}; 317 318 /* 319 * Handle a "control" request (signaled by magic being present) 320 * in the data stream. For now, we are only willing to handle 321 * window size changes. 322 */ 323 control(pty, cp, n) 324 int pty; 325 char *cp; 326 int n; 327 { 328 struct winsize w; 329 330 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 331 return (0); 332 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 333 bcopy(cp+4, (char *)&w, sizeof(w)); 334 w.ws_row = ntohs(w.ws_row); 335 w.ws_col = ntohs(w.ws_col); 336 w.ws_xpixel = ntohs(w.ws_xpixel); 337 w.ws_ypixel = ntohs(w.ws_ypixel); 338 (void)ioctl(pty, TIOCSWINSZ, &w); 339 return (4+sizeof (w)); 340 } 341 342 /* 343 * rlogin "protocol" machine. 344 */ 345 protocol(f, p) 346 int f, p; 347 { 348 char pibuf[1024], fibuf[1024], *pbp, *fbp; 349 register pcc = 0, fcc = 0; 350 int cc, nfd, pmask, fmask; 351 char cntl; 352 353 /* 354 * Must ignore SIGTTOU, otherwise we'll stop 355 * when we try and set slave pty's window shape 356 * (our controlling tty is the master pty). 357 */ 358 (void) signal(SIGTTOU, SIG_IGN); 359 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 360 if (f > p) 361 nfd = f + 1; 362 else 363 nfd = p + 1; 364 fmask = 1 << f; 365 pmask = 1 << p; 366 for (;;) { 367 int ibits, obits, ebits; 368 369 ibits = 0; 370 obits = 0; 371 if (fcc) 372 obits |= pmask; 373 else 374 ibits |= fmask; 375 if (pcc >= 0) 376 if (pcc) 377 obits |= fmask; 378 else 379 ibits |= pmask; 380 ebits = pmask; 381 if (select(nfd, &ibits, obits ? &obits : (int *)NULL, 382 &ebits, 0) < 0) { 383 if (errno == EINTR) 384 continue; 385 fatalperror(f, "select"); 386 } 387 if (ibits == 0 && obits == 0 && ebits == 0) { 388 /* shouldn't happen... */ 389 sleep(5); 390 continue; 391 } 392 #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 393 if (ebits & pmask) { 394 cc = read(p, &cntl, 1); 395 if (cc == 1 && pkcontrol(cntl)) { 396 cntl |= oobdata[0]; 397 send(f, &cntl, 1, MSG_OOB); 398 if (cntl & TIOCPKT_FLUSHWRITE) { 399 pcc = 0; 400 ibits &= ~pmask; 401 } 402 } 403 } 404 if (ibits & fmask) { 405 fcc = read(f, fibuf, sizeof(fibuf)); 406 if (fcc < 0 && errno == EWOULDBLOCK) 407 fcc = 0; 408 else { 409 register char *cp; 410 int left, n; 411 412 if (fcc <= 0) 413 break; 414 fbp = fibuf; 415 416 top: 417 for (cp = fibuf; cp < fibuf+fcc-1; cp++) 418 if (cp[0] == magic[0] && 419 cp[1] == magic[1]) { 420 left = fcc - (cp-fibuf); 421 n = control(p, cp, left); 422 if (n) { 423 left -= n; 424 if (left > 0) 425 bcopy(cp+n, cp, left); 426 fcc -= n; 427 goto top; /* n^2 */ 428 } 429 } 430 obits |= pmask; /* try write */ 431 } 432 } 433 434 if ((obits & pmask) && fcc > 0) { 435 cc = write(p, fbp, fcc); 436 if (cc > 0) { 437 fcc -= cc; 438 fbp += cc; 439 } 440 } 441 442 if (ibits & pmask) { 443 pcc = read(p, pibuf, sizeof (pibuf)); 444 pbp = pibuf; 445 if (pcc < 0 && errno == EWOULDBLOCK) 446 pcc = 0; 447 else if (pcc <= 0) 448 break; 449 else if (pibuf[0] == 0) { 450 pbp++, pcc--; 451 obits |= fmask; /* try a write */ 452 } else { 453 if (pkcontrol(pibuf[0])) { 454 pibuf[0] |= oobdata[0]; 455 send(f, &pibuf[0], 1, MSG_OOB); 456 } 457 pcc = 0; 458 } 459 } 460 if ((obits & fmask) && pcc > 0) { 461 cc = write(f, pbp, pcc); 462 if (cc < 0 && errno == EWOULDBLOCK) { 463 /* also shouldn't happen */ 464 sleep(5); 465 continue; 466 } 467 if (cc > 0) { 468 pcc -= cc; 469 pbp += cc; 470 } 471 } 472 } 473 } 474 475 cleanup() 476 { 477 char *p; 478 479 p = line + sizeof("/dev/") - 1; 480 if (logout(p)) 481 logwtmp(p, "", ""); 482 (void)chmod(line, 0666); 483 (void)chown(line, 0, 0); 484 *p = 'p'; 485 (void)chmod(line, 0666); 486 (void)chown(line, 0, 0); 487 shutdown(netf, 2); 488 exit(1); 489 } 490 491 fatal(f, msg) 492 int f; 493 char *msg; 494 { 495 char buf[BUFSIZ]; 496 497 buf[0] = '\01'; /* error indicator */ 498 (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 499 (void) write(f, buf, strlen(buf)); 500 exit(1); 501 } 502 503 fatalperror(f, msg) 504 int f; 505 char *msg; 506 { 507 char buf[BUFSIZ]; 508 extern int sys_nerr; 509 extern char *sys_errlist[]; 510 511 if ((unsigned)errno < sys_nerr) 512 (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 513 else 514 (void) sprintf(buf, "%s: Error %d", msg, errno); 515 fatal(f, buf); 516 } 517 518 #ifndef OLD_LOGIN 519 do_rlogin(host) 520 char *host; 521 { 522 523 getstr(rusername, sizeof(rusername), "remuser too long"); 524 getstr(lusername, sizeof(lusername), "locuser too long"); 525 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 526 527 if (getuid()) 528 return(-1); 529 pwd = getpwnam(lusername); 530 if (pwd == NULL) 531 return(-1); 532 return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); 533 } 534 535 536 getstr(buf, cnt, errmsg) 537 char *buf; 538 int cnt; 539 char *errmsg; 540 { 541 char c; 542 543 do { 544 if (read(0, &c, 1) != 1) 545 exit(1); 546 if (--cnt < 0) 547 fatal(1, errmsg); 548 *buf++ = c; 549 } while (c != 0); 550 } 551 552 extern char **environ; 553 554 char *speeds[] = { 555 "0", "50", "75", "110", "134", "150", "200", "300", "600", 556 "1200", "1800", "2400", "4800", "9600", "19200", "38400", 557 }; 558 #define NSPEEDS (sizeof(speeds) / sizeof(speeds[0])) 559 560 setup_term(fd) 561 int fd; 562 { 563 register char *cp = index(term, '/'), **cpp; 564 char *speed; 565 #if BSD > 43 566 struct termios tt; 567 568 tcgetattr(fd, &tt); 569 if (cp) { 570 *cp++ = '\0'; 571 speed = cp; 572 cp = index(speed, '/'); 573 if (cp) 574 *cp++ = '\0'; 575 cfsetspeed(&tt, atoi(speed)); 576 } 577 578 tt.c_iflag = TTYDEF_IFLAG; 579 tt.c_oflag = TTYDEF_OFLAG; 580 tt.c_lflag = TTYDEF_LFLAG; 581 tcsetattr(fd, TCSADFLUSH, &tt); 582 #else 583 struct sgttyb sgttyb; 584 585 (void)ioctl(fd, TIOCGETP, &sgttyb); 586 if (cp) { 587 *cp++ = '\0'; 588 speed = cp; 589 cp = index(speed, '/'); 590 if (cp) 591 *cp++ = '\0'; 592 for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) 593 if (strcmp(*cpp, speed) == 0) { 594 sgttyb.sg_ispeed = sgttyb.sg_ospeed = cpp - speeds; 595 break; 596 } 597 } 598 sgttyb.sg_flags = ECHO|CRMOD|ANYP|XTABS; 599 (void)ioctl(fd, TIOCSETP, &sgttyb); 600 #endif 601 602 env[0] = term; 603 env[1] = 0; 604 environ = env; 605 } 606 607 /* 608 * Check whether host h is in our local domain, 609 * defined as sharing the last two components of the domain part, 610 * or the entire domain part if the local domain has only one component. 611 * If either name is unqualified (contains no '.'), 612 * assume that the host is local, as it will be 613 * interpreted as such. 614 */ 615 local_domain(h) 616 char *h; 617 { 618 char localhost[MAXHOSTNAMELEN]; 619 char *p1, *p2, *topdomain(); 620 621 localhost[0] = 0; 622 (void) gethostname(localhost, sizeof(localhost)); 623 p1 = topdomain(localhost); 624 p2 = topdomain(h); 625 if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 626 return(1); 627 return(0); 628 } 629 630 char * 631 topdomain(h) 632 char *h; 633 { 634 register char *p; 635 char *maybe = NULL; 636 int dots = 0; 637 638 for (p = h + strlen(h); p >= h; p--) { 639 if (*p == '.') { 640 if (++dots == 2) 641 return (p); 642 maybe = p; 643 } 644 } 645 return (maybe); 646 } 647 #endif /* OLD_LOGIN */ 648