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