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