1 /* 2 * Copyright (c) 1983, 1988, 1989 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, 1989 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.50 (Berkeley) 10/21/90"; 26 #endif /* not lint */ 27 28 #ifdef KERBEROS 29 /* From: 30 * $Source: /mit/kerberos/ucb/mit/rlogind/RCS/rlogind.c,v $ 31 * $Header: rlogind.c,v 5.0 89/06/26 18:31:01 kfall Locked $ 32 */ 33 #endif 34 35 /* 36 * remote login server: 37 * \0 38 * remuser\0 39 * locuser\0 40 * terminal_type/speed\0 41 * data 42 */ 43 44 #define FD_SETSIZE 16 /* don't need many bits for select */ 45 #include <sys/param.h> 46 #include <sys/stat.h> 47 #include <sys/socket.h> 48 #include <sys/wait.h> 49 #include <sys/file.h> 50 #include <sys/signal.h> 51 #include <sys/ioctl.h> 52 #include <sys/termios.h> 53 54 #include <netinet/in.h> 55 #include <netinet/in_systm.h> 56 #include <netinet/ip.h> 57 58 #include <errno.h> 59 #include <pwd.h> 60 #include <netdb.h> 61 #include <syslog.h> 62 #include <string.h> 63 #include <stdio.h> 64 #include <unistd.h> 65 #include "pathnames.h" 66 67 #ifndef TIOCPKT_WINDOW 68 #define TIOCPKT_WINDOW 0x80 69 #endif 70 71 #ifdef KERBEROS 72 #include <kerberosIV/des.h> 73 #include <kerberosIV/krb.h> 74 #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 75 76 AUTH_DAT *kdata; 77 KTEXT ticket; 78 u_char auth_buf[sizeof(AUTH_DAT)]; 79 u_char tick_buf[sizeof(KTEXT_ST)]; 80 Key_schedule schedule; 81 int encrypt = 0, retval, use_kerberos = 0, vacuous = 0; 82 83 #define ARGSTR "alnkvx" 84 #else 85 #define ARGSTR "aln" 86 #endif /* KERBEROS */ 87 88 char *env[2]; 89 #define NMAX 30 90 char lusername[NMAX+1], rusername[NMAX+1]; 91 static char term[64] = "TERM="; 92 #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 93 int keepalive = 1; 94 int check_all = 0; 95 96 extern int errno; 97 int reapchild(); 98 struct passwd *getpwnam(), *pwd; 99 char *malloc(); 100 101 main(argc, argv) 102 int argc; 103 char **argv; 104 { 105 extern int opterr, optind; 106 extern int _check_rhosts_file; 107 int ch; 108 int on = 1, fromlen; 109 struct sockaddr_in from; 110 111 openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 112 113 opterr = 0; 114 while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 115 switch (ch) { 116 case 'a': 117 check_all = 1; 118 break; 119 case 'l': 120 _check_rhosts_file = 0; 121 break; 122 case 'n': 123 keepalive = 0; 124 break; 125 #ifdef KERBEROS 126 case 'k': 127 use_kerberos = 1; 128 break; 129 case 'v': 130 vacuous = 1; 131 break; 132 #ifdef CRYPT 133 case 'x': 134 encrypt = 1; 135 break; 136 #endif 137 #endif 138 case '?': 139 default: 140 usage(); 141 break; 142 } 143 argc -= optind; 144 argv += optind; 145 146 #ifdef KERBEROS 147 if (use_kerberos && vacuous) { 148 usage(); 149 fatal(STDERR_FILENO, "only one of -k and -v allowed", 0); 150 } 151 #endif 152 fromlen = sizeof (from); 153 if (getpeername(0, &from, &fromlen) < 0) { 154 syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 155 fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 156 } 157 if (keepalive && 158 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 159 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 160 on = IPTOS_LOWDELAY; 161 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 162 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 163 doit(0, &from); 164 } 165 166 int child; 167 int cleanup(); 168 int netf; 169 char line[MAXPATHLEN]; 170 int confirmed; 171 extern char *inet_ntoa(); 172 173 struct winsize win = { 0, 0, 0, 0 }; 174 175 176 doit(f, fromp) 177 int f; 178 struct sockaddr_in *fromp; 179 { 180 int i, master, pid, on = 1; 181 int authenticated = 0, hostok = 0; 182 register struct hostent *hp; 183 char remotehost[2 * MAXHOSTNAMELEN + 1]; 184 struct hostent hostent; 185 char c; 186 187 alarm(60); 188 read(f, &c, 1); 189 190 if (c != 0) 191 exit(1); 192 #ifdef KERBEROS 193 if (vacuous) 194 fatal(f, "Remote host requires Kerberos authentication", 0); 195 #endif 196 197 alarm(0); 198 fromp->sin_port = ntohs((u_short)fromp->sin_port); 199 hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 200 fromp->sin_family); 201 if (hp == 0) { 202 /* 203 * Only the name is used below. 204 */ 205 hp = &hostent; 206 hp->h_name = inet_ntoa(fromp->sin_addr); 207 hostok++; 208 } else if (check_all || local_domain(hp->h_name)) { 209 /* 210 * If name returned by gethostbyaddr is in our domain, 211 * attempt to verify that we haven't been fooled by someone 212 * in a remote net; look up the name and check that this 213 * address corresponds to the name. 214 */ 215 strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 216 remotehost[sizeof(remotehost) - 1] = 0; 217 hp = gethostbyname(remotehost); 218 if (hp) 219 for (; hp->h_addr_list[0]; hp->h_addr_list++) 220 if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 221 sizeof(fromp->sin_addr))) { 222 hostok++; 223 break; 224 } 225 } else 226 hostok++; 227 228 #ifdef KERBEROS 229 if (use_kerberos) { 230 if (!hostok) 231 fatal(f, "rlogind: Host address mismatch.", 0); 232 retval = do_krb_login(hp->h_name, fromp, encrypt); 233 if (retval == 0) 234 authenticated++; 235 else if (retval > 0) 236 fatal(f, krb_err_txt[retval], 0); 237 write(f, &c, 1); 238 confirmed = 1; /* we sent the null! */ 239 } else 240 #endif 241 { 242 if (fromp->sin_family != AF_INET || 243 fromp->sin_port >= IPPORT_RESERVED || 244 fromp->sin_port < IPPORT_RESERVED/2) { 245 syslog(LOG_NOTICE, "Connection from %s on illegal port", 246 inet_ntoa(fromp->sin_addr)); 247 fatal(f, "Permission denied", 0); 248 } 249 #ifdef IP_OPTIONS 250 { 251 u_char optbuf[BUFSIZ/3], *cp; 252 char lbuf[BUFSIZ], *lp; 253 int optsize = sizeof(optbuf), ipproto; 254 struct protoent *ip; 255 256 if ((ip = getprotobyname("ip")) != NULL) 257 ipproto = ip->p_proto; 258 else 259 ipproto = IPPROTO_IP; 260 if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 261 &optsize) == 0 && optsize != 0) { 262 lp = lbuf; 263 for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 264 sprintf(lp, " %2.2x", *cp); 265 syslog(LOG_NOTICE, 266 "Connection received using IP options (ignored):%s", 267 lbuf); 268 if (setsockopt(0, ipproto, IP_OPTIONS, 269 (char *)NULL, &optsize) != 0) { 270 syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 271 exit(1); 272 } 273 } 274 } 275 #endif 276 if (do_rlogin(hp->h_name) == 0 && hostok) 277 authenticated++; 278 } 279 if (confirmed == 0) { 280 write(f, "", 1); 281 confirmed = 1; /* we sent the null! */ 282 } 283 #ifdef KERBEROS 284 #ifdef CRYPT 285 if (encrypt) 286 (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 287 #endif 288 if (use_kerberos == 0) 289 #endif 290 if (!authenticated && !hostok) 291 write(f, "rlogind: Host address mismatch.\r\n", 292 sizeof("rlogind: Host address mismatch.\r\n") - 1); 293 294 netf = f; 295 296 pid = forkpty(&master, line, NULL, &win); 297 if (pid < 0) { 298 if (errno == ENOENT) 299 fatal(f, "Out of ptys", 0); 300 else 301 fatal(f, "Forkpty", 1); 302 } 303 if (pid == 0) { 304 if (f > 2) /* f should always be 0, but... */ 305 (void) close(f); 306 setup_term(0); 307 if (authenticated) { 308 #ifdef KERBEROS 309 if (use_kerberos && (pwd->pw_uid == 0)) 310 syslog(LOG_INFO|LOG_AUTH, 311 "ROOT Kerberos login from %s.%s@%s on %s\n", 312 kdata->pname, kdata->pinst, kdata->prealm, 313 hp->h_name); 314 #endif 315 316 execl(_PATH_LOGIN, "login", "-p", 317 "-h", hp->h_name, "-f", lusername, 0); 318 } else 319 execl(_PATH_LOGIN, "login", "-p", 320 "-h", hp->h_name, lusername, 0); 321 fatal(STDERR_FILENO, _PATH_LOGIN, 1); 322 /*NOTREACHED*/ 323 } 324 #ifdef CRYPT 325 #ifdef KERBEROS 326 /* 327 * If encrypted, don't turn on NBIO or the des read/write 328 * routines will croak. 329 */ 330 331 if (!encrypt) 332 #endif 333 #endif 334 ioctl(f, FIONBIO, &on); 335 ioctl(master, FIONBIO, &on); 336 ioctl(master, TIOCPKT, &on); 337 signal(SIGCHLD, cleanup); 338 protocol(f, master); 339 signal(SIGCHLD, SIG_IGN); 340 cleanup(); 341 } 342 343 char magic[2] = { 0377, 0377 }; 344 char oobdata[] = {TIOCPKT_WINDOW}; 345 346 /* 347 * Handle a "control" request (signaled by magic being present) 348 * in the data stream. For now, we are only willing to handle 349 * window size changes. 350 */ 351 control(pty, cp, n) 352 int pty; 353 char *cp; 354 int n; 355 { 356 struct winsize w; 357 358 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 359 return (0); 360 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 361 bcopy(cp+4, (char *)&w, sizeof(w)); 362 w.ws_row = ntohs(w.ws_row); 363 w.ws_col = ntohs(w.ws_col); 364 w.ws_xpixel = ntohs(w.ws_xpixel); 365 w.ws_ypixel = ntohs(w.ws_ypixel); 366 (void)ioctl(pty, TIOCSWINSZ, &w); 367 return (4+sizeof (w)); 368 } 369 370 /* 371 * rlogin "protocol" machine. 372 */ 373 protocol(f, p) 374 register int f, p; 375 { 376 char pibuf[1024+1], fibuf[1024], *pbp, *fbp; 377 register pcc = 0, fcc = 0; 378 int cc, nfd, n; 379 char cntl; 380 381 /* 382 * Must ignore SIGTTOU, otherwise we'll stop 383 * when we try and set slave pty's window shape 384 * (our controlling tty is the master pty). 385 */ 386 (void) signal(SIGTTOU, SIG_IGN); 387 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 388 if (f > p) 389 nfd = f + 1; 390 else 391 nfd = p + 1; 392 if (nfd > FD_SETSIZE) { 393 syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 394 fatal(f, "internal error (select mask too small)", 0); 395 } 396 for (;;) { 397 fd_set ibits, obits, ebits, *omask; 398 399 FD_ZERO(&ebits); 400 FD_ZERO(&ibits); 401 FD_ZERO(&obits); 402 omask = (fd_set *)NULL; 403 if (fcc) { 404 FD_SET(p, &obits); 405 omask = &obits; 406 } else 407 FD_SET(f, &ibits); 408 if (pcc >= 0) 409 if (pcc) { 410 FD_SET(f, &obits); 411 omask = &obits; 412 } else 413 FD_SET(p, &ibits); 414 FD_SET(p, &ebits); 415 if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 416 if (errno == EINTR) 417 continue; 418 fatal(f, "select", 1); 419 } 420 if (n == 0) { 421 /* shouldn't happen... */ 422 sleep(5); 423 continue; 424 } 425 #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 426 if (FD_ISSET(p, &ebits)) { 427 cc = read(p, &cntl, 1); 428 if (cc == 1 && pkcontrol(cntl)) { 429 cntl |= oobdata[0]; 430 send(f, &cntl, 1, MSG_OOB); 431 if (cntl & TIOCPKT_FLUSHWRITE) { 432 pcc = 0; 433 FD_CLR(p, &ibits); 434 } 435 } 436 } 437 if (FD_ISSET(f, &ibits)) { 438 #ifdef CRYPT 439 #ifdef KERBEROS 440 if (encrypt) 441 fcc = des_read(f, fibuf, sizeof(fibuf)); 442 else 443 #endif 444 #endif 445 fcc = read(f, fibuf, sizeof(fibuf)); 446 if (fcc < 0 && errno == EWOULDBLOCK) 447 fcc = 0; 448 else { 449 register char *cp; 450 int left, n; 451 452 if (fcc <= 0) 453 break; 454 fbp = fibuf; 455 456 top: 457 for (cp = fibuf; cp < fibuf+fcc-1; cp++) 458 if (cp[0] == magic[0] && 459 cp[1] == magic[1]) { 460 left = fcc - (cp-fibuf); 461 n = control(p, cp, left); 462 if (n) { 463 left -= n; 464 if (left > 0) 465 bcopy(cp+n, cp, left); 466 fcc -= n; 467 goto top; /* n^2 */ 468 } 469 } 470 FD_SET(p, &obits); /* try write */ 471 } 472 } 473 474 if (FD_ISSET(p, &obits) && fcc > 0) { 475 cc = write(p, fbp, fcc); 476 if (cc > 0) { 477 fcc -= cc; 478 fbp += cc; 479 } 480 } 481 482 if (FD_ISSET(p, &ibits)) { 483 pcc = read(p, pibuf, sizeof (pibuf)); 484 pbp = pibuf; 485 if (pcc < 0 && errno == EWOULDBLOCK) 486 pcc = 0; 487 else if (pcc <= 0) 488 break; 489 else if (pibuf[0] == 0) { 490 pbp++, pcc--; 491 #ifdef CRYPT 492 #ifdef KERBEROS 493 if (!encrypt) 494 #endif 495 #endif 496 FD_SET(f, &obits); /* try write */ 497 } else { 498 if (pkcontrol(pibuf[0])) { 499 pibuf[0] |= oobdata[0]; 500 send(f, &pibuf[0], 1, MSG_OOB); 501 } 502 pcc = 0; 503 } 504 } 505 if ((FD_ISSET(f, &obits)) && pcc > 0) { 506 #ifdef CRYPT 507 #ifdef KERBEROS 508 if (encrypt) 509 cc = des_write(f, pbp, pcc); 510 else 511 #endif 512 #endif 513 cc = write(f, pbp, pcc); 514 if (cc < 0 && errno == EWOULDBLOCK) { 515 /* 516 * This happens when we try write after read 517 * from p, but some old kernels balk at large 518 * writes even when select returns true. 519 */ 520 if (!FD_ISSET(p, &ibits)) 521 sleep(5); 522 continue; 523 } 524 if (cc > 0) { 525 pcc -= cc; 526 pbp += cc; 527 } 528 } 529 } 530 } 531 532 cleanup() 533 { 534 char *p; 535 536 p = line + sizeof(_PATH_DEV) - 1; 537 if (logout(p)) 538 logwtmp(p, "", ""); 539 (void)chmod(line, 0666); 540 (void)chown(line, 0, 0); 541 *p = 'p'; 542 (void)chmod(line, 0666); 543 (void)chown(line, 0, 0); 544 shutdown(netf, 2); 545 exit(1); 546 } 547 548 fatal(f, msg, syserr) 549 int f, syserr; 550 char *msg; 551 { 552 int len; 553 char buf[BUFSIZ], *bp = buf; 554 555 /* 556 * Prepend binary one to message if we haven't sent 557 * the magic null as confirmation. 558 */ 559 if (!confirmed) 560 *bp++ = '\01'; /* error indicator */ 561 if (syserr) 562 len = sprintf(bp, "rlogind: %s: %s.\r\n", 563 msg, strerror(errno)); 564 else 565 len = sprintf(bp, "rlogind: %s.\r\n", msg); 566 (void) write(f, buf, bp + len - buf); 567 exit(1); 568 } 569 570 do_rlogin(host) 571 char *host; 572 { 573 getstr(rusername, sizeof(rusername), "remuser too long"); 574 getstr(lusername, sizeof(lusername), "locuser too long"); 575 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 576 577 pwd = getpwnam(lusername); 578 if (pwd == NULL) 579 return(-1); 580 if (pwd->pw_uid == 0) 581 return(-1); 582 return(ruserok(host, 0, rusername, lusername)); 583 } 584 585 586 getstr(buf, cnt, errmsg) 587 char *buf; 588 int cnt; 589 char *errmsg; 590 { 591 char c; 592 593 do { 594 if (read(0, &c, 1) != 1) 595 exit(1); 596 if (--cnt < 0) 597 fatal(STDOUT_FILENO, errmsg, 0); 598 *buf++ = c; 599 } while (c != 0); 600 } 601 602 extern char **environ; 603 604 setup_term(fd) 605 int fd; 606 { 607 register char *cp = index(term+ENVSIZE, '/'); 608 char *speed; 609 struct termios tt; 610 611 #ifndef notyet 612 tcgetattr(fd, &tt); 613 if (cp) { 614 *cp++ = '\0'; 615 speed = cp; 616 cp = index(speed, '/'); 617 if (cp) 618 *cp++ = '\0'; 619 cfsetspeed(&tt, atoi(speed)); 620 } 621 622 tt.c_iflag = TTYDEF_IFLAG; 623 tt.c_oflag = TTYDEF_OFLAG; 624 tt.c_lflag = TTYDEF_LFLAG; 625 tcsetattr(fd, TCSAFLUSH, &tt); 626 #else 627 if (cp) { 628 *cp++ = '\0'; 629 speed = cp; 630 cp = index(speed, '/'); 631 if (cp) 632 *cp++ = '\0'; 633 tcgetattr(fd, &tt); 634 cfsetspeed(&tt, atoi(speed)); 635 tcsetattr(fd, TCSAFLUSH, &tt); 636 } 637 #endif 638 639 env[0] = term; 640 env[1] = 0; 641 environ = env; 642 } 643 644 #ifdef KERBEROS 645 #define VERSION_SIZE 9 646 647 /* 648 * Do the remote kerberos login to the named host with the 649 * given inet address 650 * 651 * Return 0 on valid authorization 652 * Return -1 on valid authentication, no authorization 653 * Return >0 for error conditions 654 */ 655 do_krb_login(host, dest, encrypt) 656 char *host; 657 struct sockaddr_in *dest; 658 int encrypt; 659 { 660 int rc; 661 char instance[INST_SZ], version[VERSION_SIZE]; 662 long authopts = 0L; /* !mutual */ 663 struct sockaddr_in faddr; 664 665 kdata = (AUTH_DAT *) auth_buf; 666 ticket = (KTEXT) tick_buf; 667 668 instance[0] = '*'; 669 instance[1] = '\0'; 670 671 #ifdef CRYPT 672 if (encrypt) { 673 rc = sizeof(faddr); 674 if (getsockname(0, &faddr, &rc)) 675 return(-1); 676 authopts = KOPT_DO_MUTUAL; 677 rc = krb_recvauth( 678 authopts, 0, 679 ticket, "rcmd", 680 instance, dest, &faddr, 681 kdata, "", schedule, version); 682 des_set_key(kdata->session, schedule); 683 684 } else 685 #endif 686 rc = krb_recvauth( 687 authopts, 0, 688 ticket, "rcmd", 689 instance, dest, (struct sockaddr_in *) 0, 690 kdata, "", (bit_64 *) 0, version); 691 692 if (rc != KSUCCESS) 693 return(rc); 694 695 getstr(lusername, sizeof(lusername), "locuser"); 696 /* get the "cmd" in the rcmd protocol */ 697 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 698 699 pwd = getpwnam(lusername); 700 if (pwd == NULL) 701 return(-1); 702 703 /* returns nonzero for no access */ 704 if (kuserok(kdata,lusername) != 0) 705 return(-1); 706 707 return(0); 708 709 } 710 #endif /* KERBEROS */ 711 712 usage() 713 { 714 #ifdef KERBEROS 715 syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]"); 716 #else 717 syslog(LOG_ERR, "usage: rlogind [-aln]"); 718 #endif 719 } 720 721 /* 722 * Check whether host h is in our local domain, 723 * defined as sharing the last two components of the domain part, 724 * or the entire domain part if the local domain has only one component. 725 * If either name is unqualified (contains no '.'), 726 * assume that the host is local, as it will be 727 * interpreted as such. 728 */ 729 local_domain(h) 730 char *h; 731 { 732 char localhost[MAXHOSTNAMELEN]; 733 char *p1, *p2, *topdomain(); 734 735 localhost[0] = 0; 736 (void) gethostname(localhost, sizeof(localhost)); 737 p1 = topdomain(localhost); 738 p2 = topdomain(h); 739 if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 740 return(1); 741 return(0); 742 } 743 744 char * 745 topdomain(h) 746 char *h; 747 { 748 register char *p; 749 char *maybe = NULL; 750 int dots = 0; 751 752 for (p = h + strlen(h); p >= h; p--) { 753 if (*p == '.') { 754 if (++dots == 2) 755 return (p); 756 maybe = p; 757 } 758 } 759 return (maybe); 760 } 761