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