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