1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "telnetd.h" 35 36 RCSID("$Id$"); 37 38 #if defined(_CRAY) || (defined(__hpux) && !defined(HAVE_UTMPX_H)) 39 # define PARENT_DOES_UTMP 40 #endif 41 42 #ifdef HAVE_UTMP_H 43 #include <utmp.h> 44 #endif 45 46 #ifdef HAVE_UTMPX_H 47 #include <utmpx.h> 48 #endif 49 50 #ifdef HAVE_UTMPX_H 51 struct utmpx wtmp; 52 #elif defined(HAVE_UTMP_H) 53 struct utmp wtmp; 54 #endif /* HAVE_UTMPX_H */ 55 56 #ifdef HAVE_STRUCT_UTMP_UT_HOST 57 int utmp_len = sizeof(wtmp.ut_host); 58 #else 59 int utmp_len = MaxHostNameLen; 60 #endif 61 62 #ifndef UTMP_FILE 63 #ifdef _PATH_UTMP 64 #define UTMP_FILE _PATH_UTMP 65 #else 66 #define UTMP_FILE "/etc/utmp" 67 #endif 68 #endif 69 70 /* really, mac os uses wtmpx (or asl) */ 71 #ifdef __APPLE__ 72 #undef _PATH_WTMP 73 #endif 74 75 #if !defined(WTMP_FILE) && defined(_PATH_WTMP) 76 #define WTMP_FILE _PATH_WTMP 77 #endif 78 79 #ifndef PARENT_DOES_UTMP 80 #ifdef WTMP_FILE 81 char wtmpf[] = WTMP_FILE; 82 #else 83 char wtmpf[] = "/usr/adm/wtmp"; 84 #endif 85 char utmpf[] = UTMP_FILE; 86 #else /* PARENT_DOES_UTMP */ 87 #ifdef WTMP_FILE 88 char wtmpf[] = WTMP_FILE; 89 #else 90 char wtmpf[] = "/etc/wtmp"; 91 #endif 92 #endif /* PARENT_DOES_UTMP */ 93 94 #ifdef HAVE_TMPDIR_H 95 #include <tmpdir.h> 96 #endif /* CRAY */ 97 98 #if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY) 99 #include <sys/tty.h> 100 #endif 101 #ifdef t_erase 102 #undef t_erase 103 #undef t_kill 104 #undef t_intrc 105 #undef t_quitc 106 #undef t_startc 107 #undef t_stopc 108 #undef t_eofc 109 #undef t_brkc 110 #undef t_suspc 111 #undef t_dsuspc 112 #undef t_rprntc 113 #undef t_flushc 114 #undef t_werasc 115 #undef t_lnextc 116 #endif 117 118 #ifdef HAVE_TERMIOS_H 119 #include <termios.h> 120 #else 121 #ifdef HAVE_TERMIO_H 122 #include <termio.h> 123 #endif 124 #endif 125 126 #ifdef HAVE_UTIL_H 127 #include <util.h> 128 #endif 129 #ifdef HAVE_LIBUTIL_H 130 #include <libutil.h> 131 #endif 132 133 # ifndef TCSANOW 134 # ifdef TCSETS 135 # define TCSANOW TCSETS 136 # define TCSADRAIN TCSETSW 137 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) 138 # else 139 # ifdef TCSETA 140 # define TCSANOW TCSETA 141 # define TCSADRAIN TCSETAW 142 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) 143 # else 144 # define TCSANOW TIOCSETA 145 # define TCSADRAIN TIOCSETAW 146 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) 147 # endif 148 # endif 149 # define tcsetattr(f, a, t) ioctl(f, a, t) 150 # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ 151 (tp)->c_cflag |= (val) 152 # define cfgetospeed(tp) ((tp)->c_cflag & CBAUD) 153 # ifdef CIBAUD 154 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \ 155 (tp)->c_cflag |= ((val)<<IBSHIFT) 156 # define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT) 157 # else 158 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ 159 (tp)->c_cflag |= (val) 160 # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD) 161 # endif 162 # endif /* TCSANOW */ 163 struct termios termbuf, termbuf2; /* pty control structure */ 164 # ifdef STREAMSPTY 165 static int ttyfd = -1; 166 int really_stream = 0; 167 # else 168 #define really_stream 0 169 # endif 170 171 const char *new_login = _PATH_LOGIN; 172 173 /* 174 * init_termbuf() 175 * copy_termbuf(cp) 176 * set_termbuf() 177 * 178 * These three routines are used to get and set the "termbuf" structure 179 * to and from the kernel. init_termbuf() gets the current settings. 180 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and 181 * set_termbuf() writes the structure into the kernel. 182 */ 183 184 void 185 init_termbuf(void) 186 { 187 # ifdef STREAMSPTY 188 if (really_stream) 189 tcgetattr(ttyfd, &termbuf); 190 else 191 # endif 192 tcgetattr(ourpty, &termbuf); 193 termbuf2 = termbuf; 194 } 195 196 void 197 set_termbuf(void) 198 { 199 /* 200 * Only make the necessary changes. 201 */ 202 if (memcmp(&termbuf, &termbuf2, sizeof(termbuf))) { 203 # ifdef STREAMSPTY 204 if (really_stream) 205 tcsetattr(ttyfd, TCSANOW, &termbuf); 206 else 207 # endif 208 tcsetattr(ourpty, TCSANOW, &termbuf); 209 } 210 } 211 212 213 /* 214 * spcset(func, valp, valpp) 215 * 216 * This function takes various special characters (func), and 217 * sets *valp to the current value of that character, and 218 * *valpp to point to where in the "termbuf" structure that 219 * value is kept. 220 * 221 * It returns the SLC_ level of support for this function. 222 */ 223 224 225 int 226 spcset(int func, cc_t *valp, cc_t **valpp) 227 { 228 229 #define setval(a, b) *valp = termbuf.c_cc[a]; \ 230 *valpp = &termbuf.c_cc[a]; \ 231 return(b); 232 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT); 233 234 switch(func) { 235 case SLC_EOF: 236 setval(VEOF, SLC_VARIABLE); 237 case SLC_EC: 238 setval(VERASE, SLC_VARIABLE); 239 case SLC_EL: 240 setval(VKILL, SLC_VARIABLE); 241 case SLC_IP: 242 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 243 case SLC_ABORT: 244 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 245 case SLC_XON: 246 #ifdef VSTART 247 setval(VSTART, SLC_VARIABLE); 248 #else 249 defval(0x13); 250 #endif 251 case SLC_XOFF: 252 #ifdef VSTOP 253 setval(VSTOP, SLC_VARIABLE); 254 #else 255 defval(0x11); 256 #endif 257 case SLC_EW: 258 #ifdef VWERASE 259 setval(VWERASE, SLC_VARIABLE); 260 #else 261 defval(0); 262 #endif 263 case SLC_RP: 264 #ifdef VREPRINT 265 setval(VREPRINT, SLC_VARIABLE); 266 #else 267 defval(0); 268 #endif 269 case SLC_LNEXT: 270 #ifdef VLNEXT 271 setval(VLNEXT, SLC_VARIABLE); 272 #else 273 defval(0); 274 #endif 275 case SLC_AO: 276 #if !defined(VDISCARD) && defined(VFLUSHO) 277 # define VDISCARD VFLUSHO 278 #endif 279 #ifdef VDISCARD 280 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT); 281 #else 282 defval(0); 283 #endif 284 case SLC_SUSP: 285 #ifdef VSUSP 286 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); 287 #else 288 defval(0); 289 #endif 290 #ifdef VEOL 291 case SLC_FORW1: 292 setval(VEOL, SLC_VARIABLE); 293 #endif 294 #ifdef VEOL2 295 case SLC_FORW2: 296 setval(VEOL2, SLC_VARIABLE); 297 #endif 298 case SLC_AYT: 299 #ifdef VSTATUS 300 setval(VSTATUS, SLC_VARIABLE); 301 #else 302 defval(0); 303 #endif 304 305 case SLC_BRK: 306 case SLC_SYNCH: 307 case SLC_EOR: 308 defval(0); 309 310 default: 311 *valp = 0; 312 *valpp = 0; 313 return(SLC_NOSUPPORT); 314 } 315 } 316 317 #ifdef _CRAY 318 /* 319 * getnpty() 320 * 321 * Return the number of pty's configured into the system. 322 */ 323 int 324 getnpty() 325 { 326 #ifdef _SC_CRAY_NPTY 327 int numptys; 328 329 if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1) 330 return numptys; 331 else 332 #endif /* _SC_CRAY_NPTY */ 333 return 128; 334 } 335 #endif /* CRAY */ 336 337 /* 338 * getpty() 339 * 340 * Allocate a pty. As a side effect, the external character 341 * array "line" contains the name of the slave side. 342 * 343 * Returns the file descriptor of the opened pty. 344 */ 345 346 static int ptyslavefd = -1; 347 348 static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 349 char *line = Xline; 350 351 #ifdef _CRAY 352 char myline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 353 #endif /* CRAY */ 354 355 #if !defined(HAVE_PTSNAME) && defined(STREAMSPTY) 356 static char *ptsname(int fd) 357 { 358 #ifdef HAVE_TTYNAME 359 return ttyname(fd); 360 #else 361 return NULL; 362 #endif 363 } 364 #endif 365 366 int getpty(int *ptynum) 367 { 368 #if defined(HAVE_OPENPTY) || defined(__linux) || defined(__osf__) /* XXX */ 369 { 370 int master; 371 int slave; 372 if(openpty(&master, &slave, line, 0, 0) == 0){ 373 ptyslavefd = slave; 374 return master; 375 } 376 } 377 #endif /* HAVE_OPENPTY .... */ 378 #ifdef HAVE__GETPTY 379 { 380 int master; 381 char *p; 382 p = _getpty(&master, O_RDWR, 0600, 1); 383 if(p == NULL) 384 return -1; 385 strlcpy(line, p, sizeof(Xline)); 386 return master; 387 } 388 #endif 389 390 #ifdef STREAMSPTY 391 { 392 char *clone[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm", 393 "/dev/ptym/clone", 0 }; 394 395 char **q; 396 int p; 397 for(q=clone; *q; q++){ 398 p=open(*q, O_RDWR); 399 if(p >= 0){ 400 #ifdef HAVE_GRANTPT 401 grantpt(p); 402 #endif 403 #ifdef HAVE_UNLOCKPT 404 unlockpt(p); 405 #endif 406 strlcpy(line, ptsname(p), sizeof(Xline)); 407 really_stream = 1; 408 return p; 409 } 410 } 411 } 412 #endif /* STREAMSPTY */ 413 #ifndef _CRAY 414 { 415 int p; 416 char *cp, *p1, *p2; 417 int i; 418 419 #ifndef __hpux 420 snprintf(line, sizeof(Xline), "/dev/ptyXX"); 421 p1 = &line[8]; 422 p2 = &line[9]; 423 #else 424 snprintf(line, sizeof(Xline), "/dev/ptym/ptyXX"); 425 p1 = &line[13]; 426 p2 = &line[14]; 427 #endif 428 429 430 for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) { 431 struct stat stb; 432 433 *p1 = *cp; 434 *p2 = '0'; 435 /* 436 * This stat() check is just to keep us from 437 * looping through all 256 combinations if there 438 * aren't that many ptys available. 439 */ 440 if (stat(line, &stb) < 0) 441 break; 442 for (i = 0; i < 16; i++) { 443 *p2 = "0123456789abcdef"[i]; 444 p = open(line, O_RDWR); 445 if (p > 0) { 446 #if SunOS == 40 447 int dummy; 448 #endif 449 450 #ifndef __hpux 451 line[5] = 't'; 452 #else 453 for (p1 = &line[8]; *p1; p1++) 454 *p1 = *(p1+1); 455 line[9] = 't'; 456 #endif 457 chown(line, 0, 0); 458 chmod(line, 0600); 459 #if SunOS == 40 460 if (ioctl(p, TIOCGPGRP, &dummy) == 0 461 || errno != EIO) { 462 chmod(line, 0666); 463 close(p); 464 line[5] = 'p'; 465 } else 466 #endif /* SunOS == 40 */ 467 return(p); 468 } 469 } 470 } 471 } 472 #else /* CRAY */ 473 { 474 extern lowpty, highpty; 475 struct stat sb; 476 int p; 477 478 for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) { 479 snprintf(myline, sizeof(myline), "/dev/pty/%03d", *ptynum); 480 p = open(myline, 2); 481 if (p < 0) 482 continue; 483 snprintf(line, sizeof(Xline), "/dev/ttyp%03d", *ptynum); 484 /* 485 * Here are some shenanigans to make sure that there 486 * are no listeners lurking on the line. 487 */ 488 if(stat(line, &sb) < 0) { 489 close(p); 490 continue; 491 } 492 if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) { 493 chown(line, 0, 0); 494 chmod(line, 0600); 495 close(p); 496 p = open(myline, 2); 497 if (p < 0) 498 continue; 499 } 500 /* 501 * Now it should be safe...check for accessability. 502 */ 503 if (access(line, 6) == 0) 504 return(p); 505 else { 506 /* no tty side to pty so skip it */ 507 close(p); 508 } 509 } 510 } 511 #endif /* CRAY */ 512 return(-1); 513 } 514 515 516 int 517 tty_isecho(void) 518 { 519 return (termbuf.c_lflag & ECHO); 520 } 521 522 int 523 tty_flowmode(void) 524 { 525 return((termbuf.c_iflag & IXON) ? 1 : 0); 526 } 527 528 int 529 tty_restartany(void) 530 { 531 return((termbuf.c_iflag & IXANY) ? 1 : 0); 532 } 533 534 void 535 tty_setecho(int on) 536 { 537 if (on) 538 termbuf.c_lflag |= ECHO; 539 else 540 termbuf.c_lflag &= ~ECHO; 541 } 542 543 int 544 tty_israw(void) 545 { 546 return(!(termbuf.c_lflag & ICANON)); 547 } 548 549 void 550 tty_binaryin(int on) 551 { 552 if (on) { 553 termbuf.c_iflag &= ~ISTRIP; 554 } else { 555 termbuf.c_iflag |= ISTRIP; 556 } 557 } 558 559 void 560 tty_binaryout(int on) 561 { 562 if (on) { 563 termbuf.c_cflag &= ~(CSIZE|PARENB); 564 termbuf.c_cflag |= CS8; 565 termbuf.c_oflag &= ~OPOST; 566 } else { 567 termbuf.c_cflag &= ~CSIZE; 568 termbuf.c_cflag |= CS7|PARENB; 569 termbuf.c_oflag |= OPOST; 570 } 571 } 572 573 int 574 tty_isbinaryin(void) 575 { 576 return(!(termbuf.c_iflag & ISTRIP)); 577 } 578 579 int 580 tty_isbinaryout(void) 581 { 582 return(!(termbuf.c_oflag&OPOST)); 583 } 584 585 586 int 587 tty_issofttab(void) 588 { 589 # ifdef OXTABS 590 return (termbuf.c_oflag & OXTABS); 591 # endif 592 # ifdef TABDLY 593 return ((termbuf.c_oflag & TABDLY) == TAB3); 594 # endif 595 } 596 597 void 598 tty_setsofttab(int on) 599 { 600 if (on) { 601 # ifdef OXTABS 602 termbuf.c_oflag |= OXTABS; 603 # endif 604 # ifdef TABDLY 605 termbuf.c_oflag &= ~TABDLY; 606 termbuf.c_oflag |= TAB3; 607 # endif 608 } else { 609 # ifdef OXTABS 610 termbuf.c_oflag &= ~OXTABS; 611 # endif 612 # ifdef TABDLY 613 termbuf.c_oflag &= ~TABDLY; 614 termbuf.c_oflag |= TAB0; 615 # endif 616 } 617 } 618 619 int 620 tty_islitecho(void) 621 { 622 # ifdef ECHOCTL 623 return (!(termbuf.c_lflag & ECHOCTL)); 624 # endif 625 # ifdef TCTLECH 626 return (!(termbuf.c_lflag & TCTLECH)); 627 # endif 628 # if !defined(ECHOCTL) && !defined(TCTLECH) 629 return (0); /* assumes ctl chars are echoed '^x' */ 630 # endif 631 } 632 633 void 634 tty_setlitecho(int on) 635 { 636 # ifdef ECHOCTL 637 if (on) 638 termbuf.c_lflag &= ~ECHOCTL; 639 else 640 termbuf.c_lflag |= ECHOCTL; 641 # endif 642 # ifdef TCTLECH 643 if (on) 644 termbuf.c_lflag &= ~TCTLECH; 645 else 646 termbuf.c_lflag |= TCTLECH; 647 # endif 648 } 649 650 int 651 tty_iscrnl(void) 652 { 653 return (termbuf.c_iflag & ICRNL); 654 } 655 656 /* 657 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). 658 */ 659 #if B4800 != 4800 660 #define DECODE_BAUD 661 #endif 662 663 #ifdef DECODE_BAUD 664 665 /* 666 * A table of available terminal speeds 667 */ 668 struct termspeeds { 669 int speed; 670 int value; 671 } termspeeds[] = { 672 { 0, B0 }, { 50, B50 }, { 75, B75 }, 673 { 110, B110 }, { 134, B134 }, { 150, B150 }, 674 { 200, B200 }, { 300, B300 }, { 600, B600 }, 675 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 676 { 4800, B4800 }, 677 #ifdef B7200 678 { 7200, B7200 }, 679 #endif 680 { 9600, B9600 }, 681 #ifdef B14400 682 { 14400, B14400 }, 683 #endif 684 #ifdef B19200 685 { 19200, B19200 }, 686 #endif 687 #ifdef B28800 688 { 28800, B28800 }, 689 #endif 690 #ifdef B38400 691 { 38400, B38400 }, 692 #endif 693 #ifdef B57600 694 { 57600, B57600 }, 695 #endif 696 #ifdef B115200 697 { 115200, B115200 }, 698 #endif 699 #ifdef B230400 700 { 230400, B230400 }, 701 #endif 702 { -1, 0 } 703 }; 704 #endif /* DECODE_BUAD */ 705 706 void 707 tty_tspeed(int val) 708 { 709 #ifdef DECODE_BAUD 710 struct termspeeds *tp; 711 712 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 713 ; 714 if (tp->speed == -1) /* back up to last valid value */ 715 --tp; 716 cfsetospeed(&termbuf, tp->value); 717 #else /* DECODE_BUAD */ 718 cfsetospeed(&termbuf, val); 719 #endif /* DECODE_BUAD */ 720 } 721 722 void 723 tty_rspeed(int val) 724 { 725 #ifdef DECODE_BAUD 726 struct termspeeds *tp; 727 728 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 729 ; 730 if (tp->speed == -1) /* back up to last valid value */ 731 --tp; 732 cfsetispeed(&termbuf, tp->value); 733 #else /* DECODE_BAUD */ 734 cfsetispeed(&termbuf, val); 735 #endif /* DECODE_BAUD */ 736 } 737 738 #ifdef PARENT_DOES_UTMP 739 extern struct utmp wtmp; 740 extern char wtmpf[]; 741 742 extern void utmp_sig_init (void); 743 extern void utmp_sig_reset (void); 744 extern void utmp_sig_wait (void); 745 extern void utmp_sig_notify (int); 746 # endif /* PARENT_DOES_UTMP */ 747 748 #ifdef STREAMSPTY 749 750 /* I_FIND seems to live a life of its own */ 751 static int my_find(int fd, char *module) 752 { 753 #if defined(I_FIND) && defined(I_LIST) 754 static int flag; 755 static struct str_list sl; 756 int n; 757 int i; 758 759 if(!flag){ 760 n = ioctl(fd, I_LIST, 0); 761 if(n < 0){ 762 perror("ioctl(fd, I_LIST, 0)"); 763 return -1; 764 } 765 sl.sl_modlist=(struct str_mlist*)malloc(n * sizeof(struct str_mlist)); 766 sl.sl_nmods = n; 767 n = ioctl(fd, I_LIST, &sl); 768 if(n < 0){ 769 perror("ioctl(fd, I_LIST, n)"); 770 return -1; 771 } 772 flag = 1; 773 } 774 775 for(i=0; i<sl.sl_nmods; i++) 776 if(!strcmp(sl.sl_modlist[i].l_name, module)) 777 return 1; 778 #endif 779 return 0; 780 } 781 782 static void maybe_push_modules(int fd, char **modules) 783 { 784 char **p; 785 int err; 786 787 for(p=modules; *p; p++){ 788 err = my_find(fd, *p); 789 if(err == 1) 790 break; 791 if(err < 0 && errno != EINVAL) 792 fatalperror(net, "my_find()"); 793 /* module not pushed or does not exist */ 794 } 795 /* p points to null or to an already pushed module, now push all 796 modules before this one */ 797 798 for(p--; p >= modules; p--){ 799 err = ioctl(fd, I_PUSH, *p); 800 if(err < 0 && errno != EINVAL) 801 fatalperror(net, "I_PUSH"); 802 } 803 } 804 #endif 805 806 /* 807 * getptyslave() 808 * 809 * Open the slave side of the pty, and do any initialization 810 * that is necessary. The return value is a file descriptor 811 * for the slave side. 812 */ 813 void getptyslave(void) 814 { 815 int t = -1; 816 817 struct winsize ws; 818 /* 819 * Opening the slave side may cause initilization of the 820 * kernel tty structure. We need remember the state of 821 * if linemode was turned on 822 * terminal window size 823 * terminal speed 824 * so that we can re-set them if we need to. 825 */ 826 827 828 /* 829 * Make sure that we don't have a controlling tty, and 830 * that we are the session (process group) leader. 831 */ 832 833 #ifdef HAVE_SETSID 834 if(setsid()<0) 835 fatalperror(net, "setsid()"); 836 #else 837 # ifdef TIOCNOTTY 838 t = open(_PATH_TTY, O_RDWR); 839 if (t >= 0) { 840 ioctl(t, TIOCNOTTY, (char *)0); 841 close(t); 842 } 843 # endif 844 #endif 845 846 # ifdef PARENT_DOES_UTMP 847 /* 848 * Wait for our parent to get the utmp stuff to get done. 849 */ 850 utmp_sig_wait(); 851 # endif 852 853 t = cleanopen(line); 854 if (t < 0) 855 fatalperror(net, line); 856 857 #ifdef STREAMSPTY 858 ttyfd = t; 859 860 861 /* 862 * Not all systems have (or need) modules ttcompat and pckt so 863 * don't flag it as a fatal error if they don't exist. 864 */ 865 866 if (really_stream) 867 { 868 /* these are the streams modules that we want pushed. note 869 that they are in reverse order, ptem will be pushed 870 first. maybe_push_modules() will try to push all modules 871 before the first one that isn't already pushed. i.e if 872 ldterm is pushed, only ttcompat will be attempted. 873 874 all this is because we don't know which modules are 875 available, and we don't know which modules are already 876 pushed (via autopush, for instance). 877 878 */ 879 880 char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL }; 881 char *ptymodules[] = { "pckt", NULL }; 882 883 maybe_push_modules(t, ttymodules); 884 maybe_push_modules(ourpty, ptymodules); 885 } 886 #endif 887 /* 888 * set up the tty modes as we like them to be. 889 */ 890 init_termbuf(); 891 # ifdef TIOCSWINSZ 892 if (def_row || def_col) { 893 memset(&ws, 0, sizeof(ws)); 894 ws.ws_col = def_col; 895 ws.ws_row = def_row; 896 ioctl(t, TIOCSWINSZ, (char *)&ws); 897 } 898 # endif 899 900 /* 901 * Settings for sgtty based systems 902 */ 903 904 /* 905 * Settings for UNICOS (and HPUX) 906 */ 907 # if defined(_CRAY) || defined(__hpux) 908 termbuf.c_oflag = OPOST|ONLCR|TAB3; 909 termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON; 910 termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; 911 termbuf.c_cflag = EXTB|HUPCL|CS8; 912 # endif 913 914 /* 915 * Settings for all other termios/termio based 916 * systems, other than 4.4BSD. In 4.4BSD the 917 * kernel does the initial terminal setup. 918 */ 919 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) 920 # ifndef OXTABS 921 # define OXTABS 0 922 # endif 923 termbuf.c_lflag |= ECHO; 924 termbuf.c_oflag |= ONLCR|OXTABS; 925 termbuf.c_iflag |= ICRNL; 926 termbuf.c_iflag &= ~IXOFF; 927 # endif 928 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600); 929 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600); 930 931 /* 932 * Set the tty modes, and make this our controlling tty. 933 */ 934 set_termbuf(); 935 if (login_tty(t) == -1) 936 fatalperror(net, "login_tty"); 937 if (net > 2) 938 close(net); 939 if (ourpty > 2) { 940 close(ourpty); 941 ourpty = -1; 942 } 943 } 944 945 #ifndef O_NOCTTY 946 #define O_NOCTTY 0 947 #endif 948 /* 949 * Open the specified slave side of the pty, 950 * making sure that we have a clean tty. 951 */ 952 953 int cleanopen(char *line) 954 { 955 int t; 956 957 if (ptyslavefd != -1) 958 return ptyslavefd; 959 960 #ifdef STREAMSPTY 961 if (!really_stream) 962 #endif 963 { 964 /* 965 * Make sure that other people can't open the 966 * slave side of the connection. 967 */ 968 chown(line, 0, 0); 969 chmod(line, 0600); 970 } 971 972 #ifdef HAVE_REVOKE 973 revoke(line); 974 #endif 975 976 t = open(line, O_RDWR|O_NOCTTY); 977 978 if (t < 0) 979 return(-1); 980 981 /* 982 * Hangup anybody else using this ttyp, then reopen it for 983 * ourselves. 984 */ 985 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY) 986 signal(SIGHUP, SIG_IGN); 987 #ifdef HAVE_VHANGUP 988 vhangup(); 989 #else 990 #endif 991 signal(SIGHUP, SIG_DFL); 992 t = open(line, O_RDWR|O_NOCTTY); 993 if (t < 0) 994 return(-1); 995 # endif 996 # if defined(_CRAY) && defined(TCVHUP) 997 { 998 int i; 999 signal(SIGHUP, SIG_IGN); 1000 ioctl(t, TCVHUP, (char *)0); 1001 signal(SIGHUP, SIG_DFL); 1002 1003 i = open(line, O_RDWR); 1004 1005 if (i < 0) 1006 return(-1); 1007 close(t); 1008 t = i; 1009 } 1010 # endif /* defined(CRAY) && defined(TCVHUP) */ 1011 return(t); 1012 } 1013 1014 #if !defined(BSD4_4) 1015 1016 int login_tty(int t) 1017 { 1018 /* Dont need to set this as the controlling PTY on steams sockets, 1019 * don't abort on failure. */ 1020 # if defined(TIOCSCTTY) && !defined(__hpux) 1021 if (ioctl(t, TIOCSCTTY, (char *)0) < 0 && !really_stream) 1022 fatalperror(net, "ioctl(sctty)"); 1023 # ifdef _CRAY 1024 /* 1025 * Close the hard fd to /dev/ttypXXX, and re-open through 1026 * the indirect /dev/tty interface. 1027 */ 1028 close(t); 1029 if ((t = open("/dev/tty", O_RDWR)) < 0) 1030 fatalperror(net, "open(/dev/tty)"); 1031 # endif 1032 # else 1033 /* 1034 * We get our controlling tty assigned as a side-effect 1035 * of opening up a tty device. But on BSD based systems, 1036 * this only happens if our process group is zero. The 1037 * setsid() call above may have set our pgrp, so clear 1038 * it out before opening the tty... 1039 */ 1040 #ifdef HAVE_SETPGID 1041 setpgid(0, 0); 1042 #else 1043 setpgrp(0, 0); /* if setpgid isn't available, setpgrp 1044 probably takes arguments */ 1045 #endif 1046 close(open(line, O_RDWR)); 1047 # endif 1048 if (t != 0) 1049 dup2(t, 0); 1050 if (t != 1) 1051 dup2(t, 1); 1052 if (t != 2) 1053 dup2(t, 2); 1054 if (t > 2) 1055 close(t); 1056 return(0); 1057 } 1058 #endif /* BSD <= 43 */ 1059 1060 /* 1061 * This comes from ../../bsd/tty.c and should not really be here. 1062 */ 1063 1064 /* 1065 * Clean the tty name. Return a pointer to the cleaned version. 1066 */ 1067 1068 static char * clean_ttyname (char *) __attribute__((unused)); 1069 1070 static char * 1071 clean_ttyname (char *tty) 1072 { 1073 char *res = tty; 1074 1075 if (strncmp (res, _PATH_DEV, strlen(_PATH_DEV)) == 0) 1076 res += strlen(_PATH_DEV); 1077 if (strncmp (res, "pty/", 4) == 0) 1078 res += 4; 1079 if (strncmp (res, "ptym/", 5) == 0) 1080 res += 5; 1081 return res; 1082 } 1083 1084 /* 1085 * Generate a name usable as an `ut_id', typically without `tty'. 1086 */ 1087 1088 #ifdef HAVE_STRUCT_UTMP_UT_ID 1089 static char * 1090 make_id (char *tty) 1091 { 1092 char *res = tty; 1093 1094 if (strncmp (res, "pts/", 4) == 0) 1095 res += 4; 1096 if (strncmp (res, "tty", 3) == 0) 1097 res += 3; 1098 return res; 1099 } 1100 #endif 1101 1102 /* 1103 * startslave(host) 1104 * 1105 * Given a hostname, do whatever 1106 * is necessary to startup the login process on the slave side of the pty. 1107 */ 1108 1109 /* ARGSUSED */ 1110 void 1111 startslave(const char *host, const char *utmp_host, 1112 int autologin, char *autoname) 1113 { 1114 int i; 1115 1116 #ifdef AUTHENTICATION 1117 if (!autoname || !autoname[0]) 1118 autologin = 0; 1119 1120 if (autologin < auth_level) { 1121 fatal(net, "Authorization failed"); 1122 exit(1); 1123 } 1124 #endif 1125 1126 { 1127 char *tbuf = 1128 "\r\n*** Connection not encrypted! " 1129 "Communication may be eavesdropped. ***\r\n"; 1130 #ifdef ENCRYPTION 1131 if (!no_warn && (encrypt_output == 0 || decrypt_input == 0)) 1132 #endif 1133 writenet(tbuf, strlen(tbuf)); 1134 } 1135 # ifdef PARENT_DOES_UTMP 1136 utmp_sig_init(); 1137 # endif /* PARENT_DOES_UTMP */ 1138 1139 if ((i = fork()) < 0) 1140 fatalperror(net, "fork"); 1141 if (i) { 1142 # ifdef PARENT_DOES_UTMP 1143 /* 1144 * Cray parent will create utmp entry for child and send 1145 * signal to child to tell when done. Child waits for signal 1146 * before doing anything important. 1147 */ 1148 int pid = i; 1149 void sigjob (int); 1150 1151 setpgrp(); 1152 utmp_sig_reset(); /* reset handler to default */ 1153 /* 1154 * Create utmp entry for child 1155 */ 1156 wtmp.ut_time = time(NULL); 1157 wtmp.ut_type = LOGIN_PROCESS; 1158 wtmp.ut_pid = pid; 1159 strncpy(wtmp.ut_user, "LOGIN", sizeof(wtmp.ut_user)); 1160 strncpy(wtmp.ut_host, utmp_host, sizeof(wtmp.ut_host)); 1161 strncpy(wtmp.ut_line, clean_ttyname(line), sizeof(wtmp.ut_line)); 1162 #ifdef HAVE_STRUCT_UTMP_UT_ID 1163 strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id)); 1164 #endif 1165 1166 pututline(&wtmp); 1167 endutent(); 1168 if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) { 1169 write(i, &wtmp, sizeof(struct utmp)); 1170 close(i); 1171 } 1172 #ifdef _CRAY 1173 signal(WJSIGNAL, sigjob); 1174 #endif 1175 utmp_sig_notify(pid); 1176 # endif /* PARENT_DOES_UTMP */ 1177 } else { 1178 getptyslave(); 1179 #if defined(DCE) 1180 /* if we authenticated via K5, try and join the PAG */ 1181 kerberos5_dfspag(); 1182 #endif 1183 start_login(host, autologin, autoname); 1184 /*NOTREACHED*/ 1185 } 1186 } 1187 1188 char *envinit[3]; 1189 #if !HAVE_DECL_ENVIRON 1190 extern char **environ; 1191 #endif 1192 1193 void 1194 init_env(void) 1195 { 1196 char **envp; 1197 1198 envp = envinit; 1199 if ((*envp = getenv("TZ"))) 1200 *envp++ -= 3; 1201 #if defined(_CRAY) || defined(__hpux) 1202 else 1203 *envp++ = "TZ=GMT0"; 1204 #endif 1205 *envp = 0; 1206 environ = envinit; 1207 } 1208 1209 /* 1210 * scrub_env() 1211 * 1212 * We only accept the environment variables listed below. 1213 */ 1214 1215 static void 1216 scrub_env(void) 1217 { 1218 static const char *reject[] = { 1219 "TERMCAP=/", 1220 NULL 1221 }; 1222 1223 static const char *accept[] = { 1224 "XAUTH=", "XAUTHORITY=", "DISPLAY=", 1225 "TERM=", 1226 "EDITOR=", 1227 "PAGER=", 1228 "PRINTER=", 1229 "LOGNAME=", 1230 "POSIXLY_CORRECT=", 1231 "TERMCAP=", 1232 NULL 1233 }; 1234 1235 char **cpp, **cpp2; 1236 const char **p; 1237 1238 for (cpp2 = cpp = environ; *cpp; cpp++) { 1239 int reject_it = 0; 1240 1241 for(p = reject; *p; p++) 1242 if(strncmp(*cpp, *p, strlen(*p)) == 0) { 1243 reject_it = 1; 1244 break; 1245 } 1246 if (reject_it) 1247 continue; 1248 1249 for(p = accept; *p; p++) 1250 if(strncmp(*cpp, *p, strlen(*p)) == 0) 1251 break; 1252 if(*p != NULL) 1253 *cpp2++ = *cpp; 1254 } 1255 *cpp2 = NULL; 1256 } 1257 1258 1259 struct arg_val { 1260 int size; 1261 int argc; 1262 char **argv; 1263 }; 1264 1265 static void addarg(struct arg_val*, const char*); 1266 1267 /* 1268 * start_login(host) 1269 * 1270 * Assuming that we are now running as a child processes, this 1271 * function will turn us into the login process. 1272 */ 1273 1274 void 1275 start_login(const char *host, int autologin, char *name) 1276 { 1277 struct arg_val argv; 1278 char *user; 1279 int save_errno; 1280 1281 #ifdef ENCRYPTION 1282 encrypt_output = NULL; 1283 decrypt_input = NULL; 1284 #endif 1285 1286 #ifdef HAVE_UTMPX_H 1287 { 1288 int pid = getpid(); 1289 struct utmpx utmpx; 1290 struct timeval tv; 1291 char *clean_tty; 1292 1293 /* 1294 * Create utmp entry for child 1295 */ 1296 1297 clean_tty = clean_ttyname(line); 1298 memset(&utmpx, 0, sizeof(utmpx)); 1299 strncpy(utmpx.ut_user, ".telnet", sizeof(utmpx.ut_user)); 1300 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line)); 1301 #ifdef HAVE_STRUCT_UTMP_UT_ID 1302 strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id)); 1303 #endif 1304 utmpx.ut_pid = pid; 1305 1306 utmpx.ut_type = LOGIN_PROCESS; 1307 1308 gettimeofday (&tv, NULL); 1309 utmpx.ut_tv.tv_sec = tv.tv_sec; 1310 utmpx.ut_tv.tv_usec = tv.tv_usec; 1311 1312 if (pututxline(&utmpx) == NULL) 1313 fatal(net, "pututxline failed"); 1314 } 1315 #endif 1316 1317 scrub_env(); 1318 1319 /* 1320 * -h : pass on name of host. 1321 * WARNING: -h is accepted by login if and only if 1322 * getuid() == 0. 1323 * -p : don't clobber the environment (so terminal type stays set). 1324 * 1325 * -f : force this login, he has already been authenticated 1326 */ 1327 1328 /* init argv structure */ 1329 argv.size=0; 1330 argv.argc=0; 1331 argv.argv=malloc(0); /*so we can call realloc later */ 1332 addarg(&argv, "login"); 1333 addarg(&argv, "-h"); 1334 addarg(&argv, host); 1335 addarg(&argv, "-p"); 1336 if(name && name[0]) 1337 user = name; 1338 else 1339 user = getenv("USER"); 1340 #ifdef AUTHENTICATION 1341 if (auth_level < 0 || autologin != AUTH_VALID) { 1342 if(!no_warn) { 1343 printf("User not authenticated. "); 1344 if (require_otp) 1345 printf("Using one-time password\r\n"); 1346 else 1347 printf("Using plaintext username and password\r\n"); 1348 } 1349 if (require_otp) { 1350 addarg(&argv, "-a"); 1351 addarg(&argv, "otp"); 1352 } 1353 if(log_unauth) 1354 syslog(LOG_INFO, "unauthenticated access from %s (%s)", 1355 host, user ? user : "unknown user"); 1356 } 1357 if (auth_level >= 0 && autologin == AUTH_VALID) 1358 addarg(&argv, "-f"); 1359 #endif 1360 if(user){ 1361 addarg(&argv, "--"); 1362 addarg(&argv, strdup(user)); 1363 } 1364 if (getenv("USER")) { 1365 /* 1366 * Assume that login will set the USER variable 1367 * correctly. For SysV systems, this means that 1368 * USER will no longer be set, just LOGNAME by 1369 * login. (The problem is that if the auto-login 1370 * fails, and the user then specifies a different 1371 * account name, he can get logged in with both 1372 * LOGNAME and USER in his environment, but the 1373 * USER value will be wrong. 1374 */ 1375 unsetenv("USER"); 1376 } 1377 closelog(); 1378 /* 1379 * This sleep(1) is in here so that telnetd can 1380 * finish up with the tty. There's a race condition 1381 * the login banner message gets lost... 1382 */ 1383 sleep(1); 1384 1385 execv(new_login, argv.argv); 1386 save_errno = errno; 1387 syslog(LOG_ERR, "%s: %m", new_login); 1388 fatalperror_errno(net, new_login, save_errno); 1389 /*NOTREACHED*/ 1390 } 1391 1392 static void 1393 addarg(struct arg_val *argv, const char *val) 1394 { 1395 if(argv->size <= argv->argc+1) { 1396 argv->argv = realloc(argv->argv, sizeof(char*) * (argv->size + 10)); 1397 if (argv->argv == NULL) 1398 fatal (net, "realloc: out of memory"); 1399 argv->size+=10; 1400 } 1401 if((argv->argv[argv->argc++] = strdup(val)) == NULL) 1402 fatal (net, "strdup: out of memory"); 1403 argv->argv[argv->argc] = NULL; 1404 } 1405 1406 1407 /* 1408 * rmut() 1409 * 1410 * This is the function called by cleanup() to 1411 * remove the utmp entry for this person. 1412 */ 1413 1414 #ifdef HAVE_UTMPX_H 1415 static void 1416 rmut(void) 1417 { 1418 struct utmpx utmpx, *non_save_utxp; 1419 char *clean_tty = clean_ttyname(line); 1420 1421 /* 1422 * This updates the utmpx and utmp entries and make a wtmp/x entry 1423 */ 1424 1425 setutxent(); 1426 memset(&utmpx, 0, sizeof(utmpx)); 1427 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line)); 1428 utmpx.ut_type = LOGIN_PROCESS; 1429 non_save_utxp = getutxline(&utmpx); 1430 if (non_save_utxp) { 1431 struct utmpx *utxp; 1432 struct timeval tv; 1433 char user0; 1434 1435 utxp = malloc(sizeof(struct utmpx)); 1436 *utxp = *non_save_utxp; 1437 user0 = utxp->ut_user[0]; 1438 utxp->ut_user[0] = '\0'; 1439 utxp->ut_type = DEAD_PROCESS; 1440 #ifdef HAVE_STRUCT_UTMPX_UT_EXIT 1441 #ifdef _STRUCT___EXIT_STATUS 1442 utxp->ut_exit.__e_termination = 0; 1443 utxp->ut_exit.__e_exit = 0; 1444 #elif defined(__osf__) /* XXX */ 1445 utxp->ut_exit.ut_termination = 0; 1446 utxp->ut_exit.ut_exit = 0; 1447 #else 1448 utxp->ut_exit.e_termination = 0; 1449 utxp->ut_exit.e_exit = 0; 1450 #endif 1451 #endif 1452 gettimeofday (&tv, NULL); 1453 utxp->ut_tv.tv_sec = tv.tv_sec; 1454 utxp->ut_tv.tv_usec = tv.tv_usec; 1455 1456 pututxline(utxp); 1457 #ifdef WTMPX_FILE 1458 utxp->ut_user[0] = user0; 1459 updwtmpx(WTMPX_FILE, utxp); 1460 #elif defined(WTMP_FILE) 1461 /* This is a strange system with a utmpx and a wtmp! */ 1462 { 1463 int f = open(wtmpf, O_WRONLY|O_APPEND); 1464 struct utmp wtmp; 1465 if (f >= 0) { 1466 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line)); 1467 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name)); 1468 #ifdef HAVE_STRUCT_UTMP_UT_HOST 1469 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host)); 1470 #endif 1471 wtmp.ut_time = time(NULL); 1472 write(f, &wtmp, sizeof(wtmp)); 1473 close(f); 1474 } 1475 } 1476 #endif 1477 free (utxp); 1478 } 1479 endutxent(); 1480 } /* end of rmut */ 1481 #endif 1482 1483 #if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43 1484 static void 1485 rmut(void) 1486 { 1487 int f; 1488 int found = 0; 1489 struct utmp *u, *utmp; 1490 int nutmp; 1491 struct stat statbf; 1492 char *clean_tty = clean_ttyname(line); 1493 1494 f = open(utmpf, O_RDWR); 1495 if (f >= 0) { 1496 fstat(f, &statbf); 1497 utmp = (struct utmp *)malloc((unsigned)statbf.st_size); 1498 if (!utmp) 1499 syslog(LOG_ERR, "utmp malloc failed"); 1500 if (statbf.st_size && utmp) { 1501 nutmp = read(f, utmp, (int)statbf.st_size); 1502 nutmp /= sizeof(struct utmp); 1503 1504 for (u = utmp ; u < &utmp[nutmp] ; u++) { 1505 if (strncmp(u->ut_line, 1506 clean_tty, 1507 sizeof(u->ut_line)) || 1508 u->ut_name[0]==0) 1509 continue; 1510 lseek(f, ((long)u)-((long)utmp), L_SET); 1511 strncpy(u->ut_name, "", sizeof(u->ut_name)); 1512 #ifdef HAVE_STRUCT_UTMP_UT_HOST 1513 strncpy(u->ut_host, "", sizeof(u->ut_host)); 1514 #endif 1515 u->ut_time = time(NULL); 1516 write(f, u, sizeof(wtmp)); 1517 found++; 1518 } 1519 } 1520 close(f); 1521 } 1522 if (found) { 1523 f = open(wtmpf, O_WRONLY|O_APPEND); 1524 if (f >= 0) { 1525 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line)); 1526 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name)); 1527 #ifdef HAVE_STRUCT_UTMP_UT_HOST 1528 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host)); 1529 #endif 1530 wtmp.ut_time = time(NULL); 1531 write(f, &wtmp, sizeof(wtmp)); 1532 close(f); 1533 } 1534 } 1535 chmod(line, 0666); 1536 chown(line, 0, 0); 1537 line[strlen("/dev/")] = 'p'; 1538 chmod(line, 0666); 1539 chown(line, 0, 0); 1540 } /* end of rmut */ 1541 #endif /* CRAY */ 1542 1543 #if defined(__hpux) && !defined(HAVE_UTMPX_H) 1544 static void 1545 rmut (char *line) 1546 { 1547 struct utmp utmp; 1548 struct utmp *utptr; 1549 int fd; /* for /etc/wtmp */ 1550 1551 utmp.ut_type = USER_PROCESS; 1552 strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line)); 1553 setutent(); 1554 utptr = getutline(&utmp); 1555 /* write it out only if it exists */ 1556 if (utptr) { 1557 utptr->ut_type = DEAD_PROCESS; 1558 utptr->ut_time = time(NULL); 1559 pututline(utptr); 1560 /* set wtmp entry if wtmp file exists */ 1561 if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) { 1562 write(fd, utptr, sizeof(utmp)); 1563 close(fd); 1564 } 1565 } 1566 endutent(); 1567 1568 chmod(line, 0666); 1569 chown(line, 0, 0); 1570 line[14] = line[13]; 1571 line[13] = line[12]; 1572 line[8] = 'm'; 1573 line[9] = '/'; 1574 line[10] = 'p'; 1575 line[11] = 't'; 1576 line[12] = 'y'; 1577 chmod(line, 0666); 1578 chown(line, 0, 0); 1579 } 1580 #endif 1581 1582 /* 1583 * cleanup() 1584 * 1585 * This is the routine to call when we are all through, to 1586 * clean up anything that needs to be cleaned up. 1587 */ 1588 1589 #ifdef PARENT_DOES_UTMP 1590 1591 void 1592 cleanup(int sig) 1593 { 1594 #ifdef _CRAY 1595 static int incleanup = 0; 1596 int t; 1597 int child_status; /* status of child process as returned by waitpid */ 1598 int flags = WNOHANG|WUNTRACED; 1599 1600 /* 1601 * 1: Pick up the zombie, if we are being called 1602 * as the signal handler. 1603 * 2: If we are a nested cleanup(), return. 1604 * 3: Try to clean up TMPDIR. 1605 * 4: Fill in utmp with shutdown of process. 1606 * 5: Close down the network and pty connections. 1607 * 6: Finish up the TMPDIR cleanup, if needed. 1608 */ 1609 if (sig == SIGCHLD) { 1610 while (waitpid(-1, &child_status, flags) > 0) 1611 ; /* VOID */ 1612 /* Check if the child process was stopped 1613 * rather than exited. We want cleanup only if 1614 * the child has died. 1615 */ 1616 if (WIFSTOPPED(child_status)) { 1617 return; 1618 } 1619 } 1620 t = sigblock(sigmask(SIGCHLD)); 1621 if (incleanup) { 1622 sigsetmask(t); 1623 return; 1624 } 1625 incleanup = 1; 1626 sigsetmask(t); 1627 1628 t = cleantmp(&wtmp); 1629 setutent(); /* just to make sure */ 1630 #endif /* CRAY */ 1631 rmut(line); 1632 close(ourpty); 1633 shutdown(net, 2); 1634 #ifdef _CRAY 1635 if (t == 0) 1636 cleantmp(&wtmp); 1637 #endif /* CRAY */ 1638 exit(1); 1639 } 1640 1641 #else /* PARENT_DOES_UTMP */ 1642 1643 void 1644 cleanup(int sig) 1645 { 1646 #if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP) 1647 rmut(); 1648 #ifdef HAVE_VHANGUP 1649 #ifndef __sgi 1650 vhangup(); /* XXX */ 1651 #endif 1652 #endif 1653 #else 1654 char *p; 1655 1656 p = line + sizeof("/dev/") - 1; 1657 if (logout(p)) 1658 logwtmp(p, "", ""); 1659 chmod(line, 0666); 1660 chown(line, 0, 0); 1661 *p = 'p'; 1662 chmod(line, 0666); 1663 chown(line, 0, 0); 1664 #endif 1665 shutdown(net, 2); 1666 exit(1); 1667 } 1668 1669 #endif /* PARENT_DOES_UTMP */ 1670 1671 #ifdef PARENT_DOES_UTMP 1672 /* 1673 * _utmp_sig_rcv 1674 * utmp_sig_init 1675 * utmp_sig_wait 1676 * These three functions are used to coordinate the handling of 1677 * the utmp file between the server and the soon-to-be-login shell. 1678 * The server actually creates the utmp structure, the child calls 1679 * utmp_sig_wait(), until the server calls utmp_sig_notify() and 1680 * signals the future-login shell to proceed. 1681 */ 1682 static int caught=0; /* NZ when signal intercepted */ 1683 static void (*func)(); /* address of previous handler */ 1684 1685 void 1686 _utmp_sig_rcv(sig) 1687 int sig; 1688 { 1689 caught = 1; 1690 signal(SIGUSR1, func); 1691 } 1692 1693 void 1694 utmp_sig_init() 1695 { 1696 /* 1697 * register signal handler for UTMP creation 1698 */ 1699 if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1) 1700 fatalperror(net, "telnetd/signal"); 1701 } 1702 1703 void 1704 utmp_sig_reset() 1705 { 1706 signal(SIGUSR1, func); /* reset handler to default */ 1707 } 1708 1709 # ifdef __hpux 1710 # define sigoff() /* do nothing */ 1711 # define sigon() /* do nothing */ 1712 # endif 1713 1714 void 1715 utmp_sig_wait() 1716 { 1717 /* 1718 * Wait for parent to write our utmp entry. 1719 */ 1720 sigoff(); 1721 while (caught == 0) { 1722 pause(); /* wait until we get a signal (sigon) */ 1723 sigoff(); /* turn off signals while we check caught */ 1724 } 1725 sigon(); /* turn on signals again */ 1726 } 1727 1728 void 1729 utmp_sig_notify(pid) 1730 { 1731 kill(pid, SIGUSR1); 1732 } 1733 1734 #ifdef _CRAY 1735 static int gotsigjob = 0; 1736 1737 /*ARGSUSED*/ 1738 void 1739 sigjob(sig) 1740 int sig; 1741 { 1742 int jid; 1743 struct jobtemp *jp; 1744 1745 while ((jid = waitjob(NULL)) != -1) { 1746 if (jid == 0) { 1747 return; 1748 } 1749 gotsigjob++; 1750 jobend(jid, NULL, NULL); 1751 } 1752 } 1753 1754 /* 1755 * jid_getutid: 1756 * called by jobend() before calling cleantmp() 1757 * to find the correct $TMPDIR to cleanup. 1758 */ 1759 1760 struct utmp * 1761 jid_getutid(jid) 1762 int jid; 1763 { 1764 struct utmp *cur = NULL; 1765 1766 setutent(); /* just to make sure */ 1767 while (cur = getutent()) { 1768 if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) { 1769 return(cur); 1770 } 1771 } 1772 1773 return(0); 1774 } 1775 1776 /* 1777 * Clean up the TMPDIR that login created. 1778 * The first time this is called we pick up the info 1779 * from the utmp. If the job has already gone away, 1780 * then we'll clean up and be done. If not, then 1781 * when this is called the second time it will wait 1782 * for the signal that the job is done. 1783 */ 1784 int 1785 cleantmp(wtp) 1786 struct utmp *wtp; 1787 { 1788 struct utmp *utp; 1789 static int first = 1; 1790 int mask, omask, ret; 1791 extern struct utmp *getutid (const struct utmp *_Id); 1792 1793 1794 mask = sigmask(WJSIGNAL); 1795 1796 if (first == 0) { 1797 omask = sigblock(mask); 1798 while (gotsigjob == 0) 1799 sigpause(omask); 1800 return(1); 1801 } 1802 first = 0; 1803 setutent(); /* just to make sure */ 1804 1805 utp = getutid(wtp); 1806 if (utp == 0) { 1807 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); 1808 return(-1); 1809 } 1810 /* 1811 * Nothing to clean up if the user shell was never started. 1812 */ 1813 if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0) 1814 return(1); 1815 1816 /* 1817 * Block the WJSIGNAL while we are in jobend(). 1818 */ 1819 omask = sigblock(mask); 1820 ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user); 1821 sigsetmask(omask); 1822 return(ret); 1823 } 1824 1825 int 1826 jobend(jid, path, user) 1827 int jid; 1828 char *path; 1829 char *user; 1830 { 1831 static int saved_jid = 0; 1832 static int pty_saved_jid = 0; 1833 static char saved_path[sizeof(wtmp.ut_tpath)+1]; 1834 static char saved_user[sizeof(wtmp.ut_user)+1]; 1835 1836 /* 1837 * this little piece of code comes into play 1838 * only when ptyreconnect is used to reconnect 1839 * to an previous session. 1840 * 1841 * this is the only time when the 1842 * "saved_jid != jid" code is executed. 1843 */ 1844 1845 if ( saved_jid && saved_jid != jid ) { 1846 if (!path) { /* called from signal handler */ 1847 pty_saved_jid = jid; 1848 } else { 1849 pty_saved_jid = saved_jid; 1850 } 1851 } 1852 1853 if (path) { 1854 strlcpy(saved_path, path, sizeof(saved_path)); 1855 strlcpy(saved_user, user, sizeof(saved_user)); 1856 } 1857 if (saved_jid == 0) { 1858 saved_jid = jid; 1859 return(0); 1860 } 1861 1862 /* if the jid has changed, get the correct entry from the utmp file */ 1863 1864 if ( saved_jid != jid ) { 1865 struct utmp *utp = NULL; 1866 struct utmp *jid_getutid(); 1867 1868 utp = jid_getutid(pty_saved_jid); 1869 1870 if (utp == 0) { 1871 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); 1872 return(-1); 1873 } 1874 1875 cleantmpdir(jid, utp->ut_tpath, utp->ut_user); 1876 return(1); 1877 } 1878 1879 cleantmpdir(jid, saved_path, saved_user); 1880 return(1); 1881 } 1882 1883 /* 1884 * Fork a child process to clean up the TMPDIR 1885 */ 1886 cleantmpdir(jid, tpath, user) 1887 int jid; 1888 char *tpath; 1889 char *user; 1890 { 1891 switch(fork()) { 1892 case -1: 1893 syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n", 1894 tpath); 1895 break; 1896 case 0: 1897 execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, NULL); 1898 syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n", 1899 tpath, CLEANTMPCMD); 1900 exit(1); 1901 default: 1902 /* 1903 * Forget about child. We will exit, and 1904 * /etc/init will pick it up. 1905 */ 1906 break; 1907 } 1908 } 1909 #endif /* CRAY */ 1910 #endif /* defined(PARENT_DOES_UTMP) */ 1911