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