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