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