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