rlogind.c revision 45422
1/*- 2 * Copyright (c) 1983, 1988, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char copyright[] = 36"@(#) Copyright (c) 1983, 1988, 1989, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static const char sccsid[] = "@(#)rlogind.c 8.1 (Berkeley) 6/4/93"; 43#endif 44static const char rcsid[] = 45 "$Id: rlogind.c,v 1.21 1999/04/06 23:05:58 brian Exp $"; 46#endif /* not lint */ 47 48/* 49 * remote login server: 50 * \0 51 * remuser\0 52 * locuser\0 53 * terminal_type/speed\0 54 * data 55 */ 56 57#define FD_SETSIZE 16 /* don't need many bits for select */ 58#include <sys/types.h> 59#include <sys/param.h> 60#include <sys/stat.h> 61#include <sys/ioctl.h> 62#include <signal.h> 63#include <termios.h> 64 65#include <sys/socket.h> 66#include <netinet/in.h> 67#include <netinet/in_systm.h> 68#include <netinet/ip.h> 69#include <netinet/tcp.h> 70#include <arpa/inet.h> 71#include <netdb.h> 72 73#include <errno.h> 74#include <libutil.h> 75#include <pwd.h> 76#include <syslog.h> 77#include <stdio.h> 78#include <stdlib.h> 79#include <string.h> 80#include <unistd.h> 81#include "pathnames.h" 82 83#ifndef TIOCPKT_WINDOW 84#define TIOCPKT_WINDOW 0x80 85#endif 86 87#ifdef KERBEROS 88#include <des.h> 89#include <krb.h> 90#define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 91 92AUTH_DAT *kdata; 93KTEXT ticket; 94u_char auth_buf[sizeof(AUTH_DAT)]; 95u_char tick_buf[sizeof(KTEXT_ST)]; 96Key_schedule schedule; 97int doencrypt, retval, use_kerberos, vacuous; 98 99#define ARGSTR "Dalnkvx" 100#else 101#define ARGSTR "Daln" 102#endif /* KERBEROS */ 103 104char *env[2]; 105#define NMAX 30 106char lusername[NMAX+1], rusername[NMAX+1]; 107static char term[64] = "TERM="; 108#define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 109int keepalive = 1; 110int check_all = 0; 111int no_delay; 112 113struct passwd *pwd; 114 115void doit __P((int, struct sockaddr_in *)); 116int control __P((int, char *, int)); 117void protocol __P((int, int)); 118void cleanup __P((int)); 119void fatal __P((int, char *, int)); 120int do_rlogin __P((struct sockaddr_in *)); 121void getstr __P((char *, int, char *)); 122void setup_term __P((int)); 123int do_krb_login __P((struct sockaddr_in *)); 124void usage __P((void)); 125 126int 127main(argc, argv) 128 int argc; 129 char *argv[]; 130{ 131 extern int __check_rhosts_file; 132 struct sockaddr_in from; 133 int ch, fromlen, on; 134 135 openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 136 137 opterr = 0; 138 while ((ch = getopt(argc, argv, ARGSTR)) != -1) 139 switch (ch) { 140 case 'D': 141 no_delay = 1; 142 break; 143 case 'a': 144 check_all = 1; 145 break; 146 case 'l': 147 __check_rhosts_file = 0; 148 break; 149 case 'n': 150 keepalive = 0; 151 break; 152#ifdef KERBEROS 153 case 'k': 154 use_kerberos = 1; 155 break; 156 case 'v': 157 vacuous = 1; 158 break; 159#ifdef CRYPT 160 case 'x': 161 doencrypt = 1; 162 break; 163#endif 164#endif 165 case '?': 166 default: 167 usage(); 168 break; 169 } 170 argc -= optind; 171 argv += optind; 172 173#ifdef KERBEROS 174 if (use_kerberos && vacuous) { 175 usage(); 176 fatal(STDERR_FILENO, "only one of -k and -v allowed", 0); 177 } 178#endif 179 fromlen = sizeof (from); 180 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 181 syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 182 fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 183 } 184 on = 1; 185 if (keepalive && 186 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 187 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 188 if (no_delay && 189 setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) 190 syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m"); 191 on = IPTOS_LOWDELAY; 192 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 193 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 194 195 doit(0, &from); 196 return 0; 197} 198 199int child; 200int netf; 201char line[MAXPATHLEN]; 202int confirmed; 203 204struct winsize win = { 0, 0, 0, 0 }; 205 206 207void 208doit(f, fromp) 209 int f; 210 struct sockaddr_in *fromp; 211{ 212 int master, pid, on = 1; 213 int authenticated = 0; 214 char hostname[MAXHOSTNAMELEN]; 215 char c; 216 217 alarm(60); 218 read(f, &c, 1); 219 220 if (c != 0) 221 exit(1); 222#ifdef KERBEROS 223 if (vacuous) 224 fatal(f, "Remote host requires Kerberos authentication", 0); 225#endif 226 227 alarm(0); 228 fromp->sin_port = ntohs((u_short)fromp->sin_port); 229 realhostname(hostname, sizeof(hostname) - 1, &fromp->sin_addr); 230 hostname[sizeof(hostname) - 1] = '\0'; 231 232#ifdef KERBEROS 233 if (use_kerberos) { 234 retval = do_krb_login(fromp); 235 if (retval == 0) 236 authenticated++; 237 else if (retval > 0) 238 fatal(f, krb_err_txt[retval], 0); 239 write(f, &c, 1); 240 confirmed = 1; /* we sent the null! */ 241 } else 242#endif 243 { 244 if (fromp->sin_family != AF_INET || 245 fromp->sin_port >= IPPORT_RESERVED || 246 fromp->sin_port < IPPORT_RESERVED/2) { 247 syslog(LOG_NOTICE, "Connection from %s on illegal port", 248 inet_ntoa(fromp->sin_addr)); 249 fatal(f, "Permission denied", 0); 250 } 251#ifdef IP_OPTIONS 252 { 253 u_char optbuf[BUFSIZ/3]; 254 int optsize = sizeof(optbuf), ipproto, i; 255 struct protoent *ip; 256 257 if ((ip = getprotobyname("ip")) != NULL) 258 ipproto = ip->p_proto; 259 else 260 ipproto = IPPROTO_IP; 261 if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 262 &optsize) == 0 && optsize != 0) { 263 for (i = 0; i < optsize; ) { 264 u_char c = optbuf[i]; 265 if (c == IPOPT_LSRR || c == IPOPT_SSRR) { 266 syslog(LOG_NOTICE, 267 "Connection refused from %s with IP option %s", 268 inet_ntoa(fromp->sin_addr), 269 c == IPOPT_LSRR ? "LSRR" : "SSRR"); 270 exit(1); 271 } 272 if (c == IPOPT_EOL) 273 break; 274 i += (c == IPOPT_NOP) ? 1 : optbuf[i+1]; 275 } 276 } 277 } 278#endif 279 if (do_rlogin(fromp) == 0) 280 authenticated++; 281 } 282 if (confirmed == 0) { 283 write(f, "", 1); 284 confirmed = 1; /* we sent the null! */ 285 } 286#ifdef KERBEROS 287#ifdef CRYPT 288 if (doencrypt) 289 (void) des_enc_write(f, 290 SECURE_MESSAGE, 291 strlen(SECURE_MESSAGE), 292 schedule, &kdata->session); 293#endif 294#endif 295 netf = f; 296 297 pid = forkpty(&master, line, NULL, &win); 298 if (pid < 0) { 299 if (errno == ENOENT) 300 fatal(f, "Out of ptys", 0); 301 else 302 fatal(f, "Forkpty", 1); 303 } 304 if (pid == 0) { 305 if (f > 2) /* f should always be 0, but... */ 306 (void) close(f); 307 setup_term(0); 308 if (*lusername=='-') { 309 syslog(LOG_ERR, "tried to pass user \"%s\" to login", 310 lusername); 311 fatal(STDERR_FILENO, "invalid user", 0); 312 } 313 if (authenticated) { 314#ifdef KERBEROS 315 if (use_kerberos && (pwd->pw_uid == 0)) 316 syslog(LOG_INFO|LOG_AUTH, 317 "ROOT Kerberos login from %s.%s@%s on %s\n", 318 kdata->pname, kdata->pinst, kdata->prealm, 319 hostname); 320#endif 321 322 execl(_PATH_LOGIN, "login", "-p", 323 "-h", hostname, "-f", lusername, (char *)NULL); 324 } else 325 execl(_PATH_LOGIN, "login", "-p", 326 "-h", hostname, lusername, (char *)NULL); 327 fatal(STDERR_FILENO, _PATH_LOGIN, 1); 328 /*NOTREACHED*/ 329 } 330#ifdef CRYPT 331#ifdef KERBEROS 332 /* 333 * If encrypted, don't turn on NBIO or the des read/write 334 * routines will croak. 335 */ 336 337 if (!doencrypt) 338#endif 339#endif 340 ioctl(f, FIONBIO, &on); 341 ioctl(master, FIONBIO, &on); 342 ioctl(master, TIOCPKT, &on); 343 signal(SIGCHLD, cleanup); 344 protocol(f, master); 345 signal(SIGCHLD, SIG_IGN); 346 cleanup(0); 347} 348 349char magic[2] = { 0377, 0377 }; 350char oobdata[] = {TIOCPKT_WINDOW}; 351 352/* 353 * Handle a "control" request (signaled by magic being present) 354 * in the data stream. For now, we are only willing to handle 355 * window size changes. 356 */ 357int 358control(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 */ 380void 381protocol(f, p) 382 register int f, p; 383{ 384 char pibuf[1024+1], fibuf[1024], *pbp, *fbp; 385 register pcc = 0, fcc = 0; 386 int cc, nfd, n; 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 if (nfd > FD_SETSIZE) { 401 syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 402 fatal(f, "internal error (select mask too small)", 0); 403 } 404 for (;;) { 405 fd_set ibits, obits, ebits, *omask; 406 407 FD_ZERO(&ebits); 408 FD_ZERO(&ibits); 409 FD_ZERO(&obits); 410 omask = (fd_set *)NULL; 411 if (fcc) { 412 FD_SET(p, &obits); 413 omask = &obits; 414 } else 415 FD_SET(f, &ibits); 416 if (pcc >= 0) 417 if (pcc) { 418 FD_SET(f, &obits); 419 omask = &obits; 420 } else 421 FD_SET(p, &ibits); 422 FD_SET(p, &ebits); 423 if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 424 if (errno == EINTR) 425 continue; 426 fatal(f, "select", 1); 427 } 428 if (n == 0) { 429 /* shouldn't happen... */ 430 sleep(5); 431 continue; 432 } 433#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 434 if (FD_ISSET(p, &ebits)) { 435 cc = read(p, &cntl, 1); 436 if (cc == 1 && pkcontrol(cntl)) { 437 cntl |= oobdata[0]; 438 send(f, &cntl, 1, MSG_OOB); 439 if (cntl & TIOCPKT_FLUSHWRITE) { 440 pcc = 0; 441 FD_CLR(p, &ibits); 442 } 443 } 444 } 445 if (FD_ISSET(f, &ibits)) { 446#ifdef CRYPT 447#ifdef KERBEROS 448 if (doencrypt) 449 fcc = des_enc_read(f, fibuf, sizeof(fibuf), 450 schedule, &kdata->session); 451 else 452#endif 453#endif 454 fcc = read(f, fibuf, sizeof(fibuf)); 455 if (fcc < 0 && errno == EWOULDBLOCK) 456 fcc = 0; 457 else { 458 register char *cp; 459 int left, n; 460 461 if (fcc <= 0) 462 break; 463 fbp = fibuf; 464 465 top: 466 for (cp = fibuf; cp < fibuf+fcc-1; cp++) 467 if (cp[0] == magic[0] && 468 cp[1] == magic[1]) { 469 left = fcc - (cp-fibuf); 470 n = control(p, cp, left); 471 if (n) { 472 left -= n; 473 if (left > 0) 474 bcopy(cp+n, cp, left); 475 fcc -= n; 476 goto top; /* n^2 */ 477 } 478 } 479 FD_SET(p, &obits); /* try write */ 480 } 481 } 482 483 if (FD_ISSET(p, &obits) && fcc > 0) { 484 cc = write(p, fbp, fcc); 485 if (cc > 0) { 486 fcc -= cc; 487 fbp += cc; 488 } 489 } 490 491 if (FD_ISSET(p, &ibits)) { 492 pcc = read(p, pibuf, sizeof (pibuf)); 493 pbp = pibuf; 494 if (pcc < 0 && errno == EWOULDBLOCK) 495 pcc = 0; 496 else if (pcc <= 0) 497 break; 498 else if (pibuf[0] == 0) { 499 pbp++, pcc--; 500#ifdef CRYPT 501#ifdef KERBEROS 502 if (!doencrypt) 503#endif 504#endif 505 FD_SET(f, &obits); /* try write */ 506 } else { 507 if (pkcontrol(pibuf[0])) { 508 pibuf[0] |= oobdata[0]; 509 send(f, &pibuf[0], 1, MSG_OOB); 510 } 511 pcc = 0; 512 } 513 } 514 if ((FD_ISSET(f, &obits)) && pcc > 0) { 515#ifdef CRYPT 516#ifdef KERBEROS 517 if (doencrypt) 518 cc = des_enc_write(f, pbp, pcc, 519 schedule, &kdata->session); 520 else 521#endif 522#endif 523 cc = write(f, pbp, pcc); 524 if (cc < 0 && errno == EWOULDBLOCK) { 525 /* 526 * This happens when we try write after read 527 * from p, but some old kernels balk at large 528 * writes even when select returns true. 529 */ 530 if (!FD_ISSET(p, &ibits)) 531 sleep(5); 532 continue; 533 } 534 if (cc > 0) { 535 pcc -= cc; 536 pbp += cc; 537 } 538 } 539 } 540} 541 542void 543cleanup(signo) 544 int signo; 545{ 546 char *p; 547 548 p = line + sizeof(_PATH_DEV) - 1; 549 if (logout(p)) 550 logwtmp(p, "", ""); 551 (void)chmod(line, 0666); 552 (void)chown(line, 0, 0); 553 *p = 'p'; 554 (void)chmod(line, 0666); 555 (void)chown(line, 0, 0); 556 shutdown(netf, 2); 557 exit(1); 558} 559 560void 561fatal(f, msg, syserr) 562 int f; 563 char *msg; 564 int syserr; 565{ 566 int len; 567 char buf[BUFSIZ], *bp = buf; 568 569 /* 570 * Prepend binary one to message if we haven't sent 571 * the magic null as confirmation. 572 */ 573 if (!confirmed) 574 *bp++ = '\01'; /* error indicator */ 575 if (syserr) 576 len = sprintf(bp, "rlogind: %s: %s.\r\n", 577 msg, strerror(errno)); 578 else 579 len = sprintf(bp, "rlogind: %s.\r\n", msg); 580 (void) write(f, buf, bp + len - buf); 581 exit(1); 582} 583 584int 585do_rlogin(dest) 586 struct sockaddr_in *dest; 587{ 588 getstr(rusername, sizeof(rusername), "remuser too long"); 589 getstr(lusername, sizeof(lusername), "locuser too long"); 590 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 591 592 pwd = getpwnam(lusername); 593 if (pwd == NULL) 594 return (-1); 595 /* XXX why don't we syslog() failure? */ 596 return (iruserok(dest->sin_addr.s_addr, pwd->pw_uid == 0, 597 rusername, lusername)); 598} 599 600void 601getstr(buf, cnt, errmsg) 602 char *buf; 603 int cnt; 604 char *errmsg; 605{ 606 char c; 607 608 do { 609 if (read(0, &c, 1) != 1) 610 exit(1); 611 if (--cnt < 0) 612 fatal(STDOUT_FILENO, errmsg, 0); 613 *buf++ = c; 614 } while (c != 0); 615} 616 617extern char **environ; 618 619void 620setup_term(fd) 621 int fd; 622{ 623 register char *cp = index(term+ENVSIZE, '/'); 624 char *speed; 625 struct termios tt; 626 627#ifndef notyet 628 tcgetattr(fd, &tt); 629 if (cp) { 630 *cp++ = '\0'; 631 speed = cp; 632 cp = index(speed, '/'); 633 if (cp) 634 *cp++ = '\0'; 635 cfsetspeed(&tt, atoi(speed)); 636 } 637 638 tt.c_iflag = TTYDEF_IFLAG; 639 tt.c_oflag = TTYDEF_OFLAG; 640 tt.c_lflag = TTYDEF_LFLAG; 641 tcsetattr(fd, TCSAFLUSH, &tt); 642#else 643 if (cp) { 644 *cp++ = '\0'; 645 speed = cp; 646 cp = index(speed, '/'); 647 if (cp) 648 *cp++ = '\0'; 649 tcgetattr(fd, &tt); 650 cfsetspeed(&tt, atoi(speed)); 651 tcsetattr(fd, TCSAFLUSH, &tt); 652 } 653#endif 654 655 env[0] = term; 656 env[1] = 0; 657 environ = env; 658} 659 660#ifdef KERBEROS 661#define VERSION_SIZE 9 662 663/* 664 * Do the remote kerberos login to the named host with the 665 * given inet address 666 * 667 * Return 0 on valid authorization 668 * Return -1 on valid authentication, no authorization 669 * Return >0 for error conditions 670 */ 671int 672do_krb_login(dest) 673 struct sockaddr_in *dest; 674{ 675 int rc; 676 char instance[INST_SZ], version[VERSION_SIZE]; 677 long authopts = 0L; /* !mutual */ 678 struct sockaddr_in faddr; 679 680 kdata = (AUTH_DAT *) auth_buf; 681 ticket = (KTEXT) tick_buf; 682 683 instance[0] = '*'; 684 instance[1] = '\0'; 685 686#ifdef CRYPT 687 if (doencrypt) { 688 rc = sizeof(faddr); 689 if (getsockname(0, (struct sockaddr *)&faddr, &rc)) 690 return (-1); 691 authopts = KOPT_DO_MUTUAL; 692 rc = krb_recvauth( 693 authopts, 0, 694 ticket, "rcmd", 695 instance, dest, &faddr, 696 kdata, "", schedule, version); 697 des_set_key(&kdata->session, schedule); 698 699 } else 700#endif 701 rc = krb_recvauth( 702 authopts, 0, 703 ticket, "rcmd", 704 instance, dest, (struct sockaddr_in *) 0, 705 kdata, "", NULL, version); 706 707 if (rc != KSUCCESS) 708 return (rc); 709 710 getstr(lusername, sizeof(lusername), "locuser"); 711 /* get the "cmd" in the rcmd protocol */ 712 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 713 714 pwd = getpwnam(lusername); 715 if (pwd == NULL) 716 return (-1); 717 718 /* returns nonzero for no access */ 719 if (kuserok(kdata, lusername) != 0) 720 return (-1); 721 722 return (0); 723 724} 725#endif /* KERBEROS */ 726 727void 728usage() 729{ 730#ifdef KERBEROS 731 syslog(LOG_ERR, "usage: rlogind [-Daln] [-k | -v]"); 732#else 733 syslog(LOG_ERR, "usage: rlogind [-Daln]"); 734#endif 735} 736