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.22.1.1 (Berkeley) 01/06/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 * Automatic login protocol is done here, using login -f upon success, 37 * unless OLD_LOGIN is defined (then done in login, ala 4.2/4.3BSD). 38 */ 39 40 #include <stdio.h> 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #include <sys/socket.h> 44 #include <sys/wait.h> 45 #include <sys/file.h> 46 47 #include <netinet/in.h> 48 49 #include <errno.h> 50 #include <pwd.h> 51 #include <signal.h> 52 #ifndef TERMIOS 53 #include <sgtty.h> 54 #else /* TERMIOS */ 55 #include <sys/ioctl.h> 56 #include <sys/termios.h> 57 #endif /* TERMIOS */ 58 #include <stdio.h> 59 #include <netdb.h> 60 #include <syslog.h> 61 #include <strings.h> 62 63 #ifndef TIOCPKT_WINDOW 64 #define TIOCPKT_WINDOW 0x80 65 #endif 66 67 #ifdef KERBEROS 68 #include <sys/param.h> 69 #include <kerberos/krb.h> 70 #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 71 72 AUTH_DAT *kdata; 73 KTEXT ticket; 74 u_char auth_buf[sizeof(AUTH_DAT)]; 75 u_char tick_buf[sizeof(KTEXT_ST)]; 76 Key_schedule schedule; 77 int encrypt, retval; 78 int do_krb_login(); 79 80 #define OLD_RCMD 0x00 81 #define KERB_RCMD 0x01 82 #define KERB_RCMD_MUTUAL 0x02 83 #endif /* KERBEROS */ 84 85 char *env[2]; 86 #define NMAX 30 87 char lusername[NMAX+1], rusername[NMAX+1]; 88 static char term[64] = "TERM="; 89 #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 90 int keepalive = 1; 91 92 #define SUPERUSER(pwd) ((pwd)->pw_uid == 0) 93 94 extern int errno; 95 int reapchild(); 96 struct passwd *getpwnam(), *pwd; 97 char *malloc(); 98 99 main(argc, argv) 100 int argc; 101 char **argv; 102 { 103 extern int opterr, optind, _check_rhosts_file; 104 int ch; 105 int on = 1, fromlen; 106 struct sockaddr_in from; 107 108 openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH); 109 110 opterr = 0; 111 while ((ch = getopt(argc, argv, "ln")) != EOF) 112 switch (ch) { 113 case 'l': 114 _check_rhosts_file = 0; 115 break; 116 case 'n': 117 keepalive = 0; 118 break; 119 case '?': 120 default: 121 syslog(LOG_ERR, "usage: rlogind [-l] [-n]"); 122 break; 123 } 124 argc -= optind; 125 argv += optind; 126 127 fromlen = sizeof (from); 128 if (getpeername(0, &from, &fromlen) < 0) { 129 fprintf(stderr, "%s: ", argv[0]); 130 perror("getpeername"); 131 exit(1); 132 } 133 if (keepalive && 134 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 135 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 136 doit(0, &from); 137 } 138 139 int child; 140 int cleanup(); 141 int netf; 142 char *line; 143 extern char *inet_ntoa(); 144 145 struct winsize win = { 0, 0, 0, 0 }; 146 147 148 doit(f, fromp) 149 int f; 150 struct sockaddr_in *fromp; 151 { 152 int i, p, t, pid, on = 1; 153 #ifndef OLD_LOGIN 154 int authenticated = 0; 155 #endif 156 register struct hostent *hp; 157 struct hostent hostent; 158 char c; 159 160 alarm(60); 161 read(f, &c, 1); 162 163 #ifdef KERBEROS 164 /* 165 * XXX 1st char tells us which client we're talking to 166 */ 167 switch (c) { 168 169 case KERB_RCMD: 170 break; 171 172 case KERB_RCMD_MUTUAL: 173 encrypt = 1; 174 break; 175 176 177 case OLD_RCMD: 178 default: 179 fatal(f, "Remote host requires Kerberos authentication"); 180 } 181 #else 182 if (c != 0) 183 exit(1); 184 #endif 185 186 alarm(0); 187 fromp->sin_port = ntohs((u_short)fromp->sin_port); 188 hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 189 fromp->sin_family); 190 if (hp == 0) { 191 /* 192 * Only the name is used below. 193 */ 194 hp = &hostent; 195 hp->h_name = inet_ntoa(fromp->sin_addr); 196 } 197 198 #ifdef KERBEROS 199 retval = do_krb_login(hp->h_name, fromp, encrypt); 200 write(f, &c, 1); 201 if (retval == 0) 202 authenticated++; 203 else 204 if (retval > 0) 205 fatal(f, krb_err_txt[retval]); 206 #else 207 if (fromp->sin_family != AF_INET || 208 fromp->sin_port >= IPPORT_RESERVED || 209 fromp->sin_port < IPPORT_RESERVED/2) 210 fatal(f, "Permission denied"); 211 write(f, "", 1); 212 #endif 213 #ifndef OLD_LOGIN 214 if (do_rlogin(hp->h_name) == 0) 215 authenticated++; 216 #endif 217 218 for (c = 'p'; c <= 's'; c++) { 219 struct stat stb; 220 line = "/dev/ptyXX"; 221 line[strlen("/dev/pty")] = c; 222 line[strlen("/dev/ptyp")] = '0'; 223 if (stat(line, &stb) < 0) 224 break; 225 for (i = 0; i < 16; i++) { 226 line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 227 p = open(line, O_RDWR); 228 if (p > 0) 229 goto gotpty; 230 } 231 } 232 fatal(f, "Out of ptys"); 233 /*NOTREACHED*/ 234 gotpty: 235 (void) ioctl(p, TIOCSWINSZ, &win); 236 netf = f; 237 line[strlen("/dev/")] = 't'; 238 t = open(line, O_RDWR); 239 if (t < 0) 240 fatalperror(f, line); 241 if (fchmod(t, 0)) 242 fatalperror(f, line); 243 (void)signal(SIGHUP, SIG_IGN); 244 vhangup(); 245 (void)signal(SIGHUP, SIG_DFL); 246 t = open(line, O_RDWR); 247 if (t < 0) 248 fatalperror(f, line); 249 setup_term(t); 250 #ifdef DEBUG 251 { 252 int tt = open("/dev/tty", O_RDWR); 253 if (tt > 0) { 254 (void)ioctl(tt, TIOCNOTTY, 0); 255 (void)close(tt); 256 } 257 } 258 #endif 259 pid = fork(); 260 if (pid < 0) 261 fatalperror(f, ""); 262 if (pid == 0) { 263 #ifdef TERMIOS 264 if (setsid() < 0) 265 fatalperror(f, "setsid"); 266 if (ioctl(t, TIOCSCTTY, 0) < 0) 267 fatalperror(f, "ioctl(sctty)"); 268 #endif /* TERMIOS */ 269 close(f), close(p); 270 dup2(t, 0), dup2(t, 1), dup2(t, 2); 271 close(t); 272 #ifdef OLD_LOGIN 273 execl("/bin/login", "login", "-r", hp->h_name, 0); 274 #else /* OLD_LOGIN */ 275 if (authenticated) 276 execl("/bin/login", "login", "-p", "-f", 277 "-h", hp->h_name, lusername, 0); 278 else 279 execl("/bin/login", "login", "-p", "-h", hp->h_name, 280 lusername, 0); 281 #endif /* OLD_LOGIN */ 282 fatalperror(2, "/bin/login"); 283 /*NOTREACHED*/ 284 } 285 close(t); 286 287 #ifdef KERBEROS 288 /* 289 * If encrypted, don't turn on NBIO or the des read/write 290 * routines will croak. 291 */ 292 293 if (encrypt) 294 (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 295 else 296 #endif 297 ioctl(f, FIONBIO, &on); 298 ioctl(p, FIONBIO, &on); 299 ioctl(p, TIOCPKT, &on); 300 signal(SIGTSTP, SIG_IGN); 301 signal(SIGCHLD, cleanup); 302 setpgrp(0, 0); 303 protocol(f, p); 304 signal(SIGCHLD, SIG_IGN); 305 cleanup(); 306 } 307 308 char magic[2] = { 0377, 0377 }; 309 char oobdata[] = {TIOCPKT_WINDOW}; 310 311 /* 312 * Handle a "control" request (signaled by magic being present) 313 * in the data stream. For now, we are only willing to handle 314 * window size changes. 315 */ 316 control(pty, cp, n) 317 int pty; 318 char *cp; 319 int n; 320 { 321 struct winsize w; 322 323 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 324 return (0); 325 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 326 bcopy(cp+4, (char *)&w, sizeof(w)); 327 w.ws_row = ntohs(w.ws_row); 328 w.ws_col = ntohs(w.ws_col); 329 w.ws_xpixel = ntohs(w.ws_xpixel); 330 w.ws_ypixel = ntohs(w.ws_ypixel); 331 (void)ioctl(pty, TIOCSWINSZ, &w); 332 return (4+sizeof (w)); 333 } 334 335 /* 336 * rlogin "protocol" machine. 337 */ 338 protocol(f, p) 339 int f, p; 340 { 341 char pibuf[1024], fibuf[1024], *pbp, *fbp; 342 register pcc = 0, fcc = 0; 343 int cc, nfd, pmask, fmask; 344 char cntl; 345 346 /* 347 * Must ignore SIGTTOU, otherwise we'll stop 348 * when we try and set slave pty's window shape 349 * (our controlling tty is the master pty). 350 */ 351 (void) signal(SIGTTOU, SIG_IGN); 352 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 353 if (f > p) 354 nfd = f + 1; 355 else 356 nfd = p + 1; 357 fmask = 1 << f; 358 pmask = 1 << p; 359 for (;;) { 360 int ibits, obits, ebits; 361 362 ibits = 0; 363 obits = 0; 364 if (fcc) 365 obits |= pmask; 366 else 367 ibits |= fmask; 368 if (pcc >= 0) 369 if (pcc) 370 obits |= fmask; 371 else 372 ibits |= pmask; 373 ebits = pmask; 374 if (select(nfd, &ibits, obits ? &obits : (int *)NULL, 375 &ebits, 0) < 0) { 376 if (errno == EINTR) 377 continue; 378 fatalperror(f, "select"); 379 } 380 if (ibits == 0 && obits == 0 && ebits == 0) { 381 /* shouldn't happen... */ 382 sleep(5); 383 continue; 384 } 385 #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 386 if (ebits & pmask) { 387 cc = read(p, &cntl, 1); 388 if (cc == 1 && pkcontrol(cntl)) { 389 cntl |= oobdata[0]; 390 send(f, &cntl, 1, MSG_OOB); 391 if (cntl & TIOCPKT_FLUSHWRITE) { 392 pcc = 0; 393 ibits &= ~pmask; 394 } 395 } 396 } 397 if (ibits & fmask) { 398 #ifdef KERBEROS 399 if (encrypt) 400 fcc = des_read(f, fibuf, sizeof(fibuf)); 401 else 402 #endif 403 fcc = read(f, fibuf, sizeof(fibuf)); 404 if (fcc < 0 && errno == EWOULDBLOCK) 405 fcc = 0; 406 else { 407 register char *cp; 408 int left, n; 409 410 if (fcc <= 0) 411 break; 412 fbp = fibuf; 413 414 top: 415 for (cp = fibuf; cp < fibuf+fcc-1; cp++) 416 if (cp[0] == magic[0] && 417 cp[1] == magic[1]) { 418 left = fcc - (cp-fibuf); 419 n = control(p, cp, left); 420 if (n) { 421 left -= n; 422 if (left > 0) 423 bcopy(cp+n, cp, left); 424 fcc -= n; 425 goto top; /* n^2 */ 426 } 427 } 428 obits |= pmask; /* try write */ 429 } 430 } 431 432 if ((obits & pmask) && fcc > 0) { 433 cc = write(p, fbp, fcc); 434 if (cc > 0) { 435 fcc -= cc; 436 fbp += cc; 437 } 438 } 439 440 if (ibits & pmask) { 441 pcc = read(p, pibuf, sizeof (pibuf)); 442 pbp = pibuf; 443 if (pcc < 0 && errno == EWOULDBLOCK) 444 pcc = 0; 445 else if (pcc <= 0) 446 break; 447 else if (pibuf[0] == 0) { 448 pbp++, pcc--; 449 #ifdef KERBEROS 450 if (!encrypt) 451 #endif 452 obits |= fmask; /* try a 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 ((obits & fmask) && pcc > 0) { 462 #ifdef KERBEROS 463 if (encrypt) 464 cc = des_write(f, pbp, pcc); 465 else 466 #endif 467 cc = write(f, pbp, pcc); 468 if (cc < 0 && errno == EWOULDBLOCK) { 469 /* also shouldn't happen */ 470 sleep(5); 471 continue; 472 } 473 if (cc > 0) { 474 pcc -= cc; 475 pbp += cc; 476 } 477 } 478 } 479 } 480 481 cleanup() 482 { 483 char *p; 484 485 p = line + sizeof("/dev/") - 1; 486 if (logout(p)) 487 logwtmp(p, "", ""); 488 (void)chmod(line, 0666); 489 (void)chown(line, 0, 0); 490 *p = 'p'; 491 (void)chmod(line, 0666); 492 (void)chown(line, 0, 0); 493 shutdown(netf, 2); 494 exit(1); 495 } 496 497 fatal(f, msg) 498 int f; 499 char *msg; 500 { 501 char buf[BUFSIZ]; 502 503 buf[0] = '\01'; /* error indicator */ 504 (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 505 (void) write(f, buf, strlen(buf)); 506 exit(1); 507 } 508 509 fatalperror(f, msg) 510 int f; 511 char *msg; 512 { 513 char buf[BUFSIZ]; 514 extern int sys_nerr; 515 extern char *sys_errlist[]; 516 517 if ((unsigned)errno < sys_nerr) 518 (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 519 else 520 (void) sprintf(buf, "%s: Error %d", msg, errno); 521 fatal(f, buf); 522 } 523 524 #ifndef OLD_LOGIN 525 do_rlogin(host) 526 char *host; 527 { 528 529 getstr(rusername, sizeof(rusername), "remuser too long"); 530 getstr(lusername, sizeof(lusername), "locuser too long"); 531 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 532 533 if (getuid()) 534 return(-1); 535 pwd = getpwnam(lusername); 536 if (pwd == NULL) 537 return(-1); 538 return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); 539 } 540 541 542 getstr(buf, cnt, errmsg) 543 char *buf; 544 int cnt; 545 char *errmsg; 546 { 547 char c; 548 549 do { 550 if (read(0, &c, 1) != 1) 551 exit(1); 552 if (--cnt < 0) 553 fatal(1, errmsg); 554 *buf++ = c; 555 } while (c != 0); 556 } 557 558 extern char **environ; 559 560 #ifdef TERMIOS 561 setup_term(fd) 562 int fd; 563 { 564 struct termios tt; 565 register char *cp = index(term+ENVSIZE, '/'); 566 char *speed; 567 568 tcgetattr(fd, &tt); 569 if (cp) { 570 *cp++ = '\0'; 571 speed = cp; 572 cp = index(speed, '/'); 573 if (cp) 574 *cp++ = '\0'; 575 cfsetspeed(&tt, atoi(speed)); 576 } 577 tt.c_iflag = BRKINT|ICRNL|IXON|ISTRIP|IEXTEN|IMAXBEL; 578 tt.c_oflag = OPOST|ONLCR|OXTABS; 579 tt.c_lflag = ISIG|ICANON|ECHO; 580 tcsetattr(fd, TCSADFLUSH, &tt); 581 582 env[0] = term; 583 env[1] = 0; 584 environ = env; 585 } 586 #else /* TERMIOS */ 587 char *speeds[] = { 588 "0", "50", "75", "110", "134", "150", "200", "300", "600", 589 "1200", "1800", "2400", "4800", "9600", "19200", "38400", 590 }; 591 #define NSPEEDS (sizeof(speeds) / sizeof(speeds[0])) 592 593 setup_term(fd) 594 int fd; 595 { 596 register char *cp = index(term, '/'), **cpp; 597 struct sgttyb sgttyb; 598 char *speed; 599 600 (void)ioctl(fd, TIOCGETP, &sgttyb); 601 if (cp) { 602 *cp++ = '\0'; 603 speed = cp; 604 cp = index(speed, '/'); 605 if (cp) 606 *cp++ = '\0'; 607 for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) 608 if (strcmp(*cpp, speed) == 0) { 609 sgttyb.sg_ispeed = sgttyb.sg_ospeed = cpp - speeds; 610 break; 611 } 612 } 613 sgttyb.sg_flags = ECHO|CRMOD|ANYP|XTABS; 614 (void)ioctl(fd, TIOCSETP, &sgttyb); 615 616 env[0] = term; 617 env[1] = 0; 618 environ = env; 619 } 620 #endif /* TERMIOS */ 621 #endif /* OLD_LOGIN */ 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 /* XXX need to use something other than ruserok */ 686 /* returns -1 for invalid authentication */ 687 return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); 688 } 689 #endif /* KERBEROS */ 690