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