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