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