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