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