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