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