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