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