sys_term.c revision 78527
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 36RCSID("$Id: sys_term.c,v 1.100 2001/04/24 23:11:43 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 51struct utmpx wtmp; 52#elif defined(HAVE_UTMP_H) 53struct utmp wtmp; 54#endif /* HAVE_UTMPX_H */ 55 56#ifdef HAVE_STRUCT_UTMP_UT_HOST 57int utmp_len = sizeof(wtmp.ut_host); 58#else 59int 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 76char wtmpf[] = WTMP_FILE; 77#else 78char wtmpf[] = "/usr/adm/wtmp"; 79#endif 80char utmpf[] = UTMP_FILE; 81#else /* PARENT_DOES_UTMP */ 82#ifdef WTMP_FILE 83char wtmpf[] = WTMP_FILE; 84#else 85char 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 207void 208set_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 235int 236spcset(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 */ 333int 334getnpty() 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 356static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 357char *line = Xline; 358 359#ifdef _CRAY 360char 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) 364static char *ptsname(int fd) 365{ 366#ifdef HAVE_TTYNAME 367 return ttyname(fd); 368#else 369 return NULL; 370#endif 371} 372#endif 373 374int 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 523int 524tty_isecho(void) 525{ 526 return (termbuf.c_lflag & ECHO); 527} 528 529int 530tty_flowmode(void) 531{ 532 return((termbuf.c_iflag & IXON) ? 1 : 0); 533} 534 535int 536tty_restartany(void) 537{ 538 return((termbuf.c_iflag & IXANY) ? 1 : 0); 539} 540 541void 542tty_setecho(int on) 543{ 544 if (on) 545 termbuf.c_lflag |= ECHO; 546 else 547 termbuf.c_lflag &= ~ECHO; 548} 549 550int 551tty_israw(void) 552{ 553 return(!(termbuf.c_lflag & ICANON)); 554} 555 556void 557tty_binaryin(int on) 558{ 559 if (on) { 560 termbuf.c_iflag &= ~ISTRIP; 561 } else { 562 termbuf.c_iflag |= ISTRIP; 563 } 564} 565 566void 567tty_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 580int 581tty_isbinaryin(void) 582{ 583 return(!(termbuf.c_iflag & ISTRIP)); 584} 585 586int 587tty_isbinaryout(void) 588{ 589 return(!(termbuf.c_oflag&OPOST)); 590} 591 592 593int 594tty_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 604void 605tty_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 626int 627tty_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 640void 641tty_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 657int 658tty_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 */ 675struct 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 713void 714tty_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 729void 730tty_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 746extern struct utmp wtmp; 747extern char wtmpf[]; 748 749extern void utmp_sig_init (void); 750extern void utmp_sig_reset (void); 751extern void utmp_sig_wait (void); 752extern 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 */ 758static 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 789static 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 */ 820void 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 962int 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 1022int 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 1072static char * 1073clean_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 1091static char * 1092make_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 */ 1112void 1113startslave(const char *host, const char *utmp_host, 1114 int autologin, char *autoname) 1115{ 1116 int i; 1117 1118#ifdef AUTHENTICATION 1119 if (!autoname || !autoname[0]) 1120 autologin = 0; 1121 1122 if (autologin < auth_level) { 1123 fatal(net, "Authorization failed"); 1124 exit(1); 1125 } 1126#endif 1127 1128 { 1129 char *tbuf = 1130 "\r\n*** Connection not encrypted! " 1131 "Communication may be eavesdropped. ***\r\n"; 1132#ifdef ENCRYPTION 1133 if (!no_warn && (encrypt_output == 0 || decrypt_input == 0)) 1134#endif 1135 writenet((unsigned char*)tbuf, strlen(tbuf)); 1136 } 1137# ifdef PARENT_DOES_UTMP 1138 utmp_sig_init(); 1139# endif /* PARENT_DOES_UTMP */ 1140 1141 if ((i = fork()) < 0) 1142 fatalperror(net, "fork"); 1143 if (i) { 1144# ifdef PARENT_DOES_UTMP 1145 /* 1146 * Cray parent will create utmp entry for child and send 1147 * signal to child to tell when done. Child waits for signal 1148 * before doing anything important. 1149 */ 1150 int pid = i; 1151 void sigjob (int); 1152 1153 setpgrp(); 1154 utmp_sig_reset(); /* reset handler to default */ 1155 /* 1156 * Create utmp entry for child 1157 */ 1158 wtmp.ut_time = time(NULL); 1159 wtmp.ut_type = LOGIN_PROCESS; 1160 wtmp.ut_pid = pid; 1161 strncpy(wtmp.ut_user, "LOGIN", sizeof(wtmp.ut_user)); 1162 strncpy(wtmp.ut_host, utmp_host, sizeof(wtmp.ut_host)); 1163 strncpy(wtmp.ut_line, clean_ttyname(line), sizeof(wtmp.ut_line)); 1164#ifdef HAVE_STRUCT_UTMP_UT_ID 1165 strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id)); 1166#endif 1167 1168 pututline(&wtmp); 1169 endutent(); 1170 if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) { 1171 write(i, &wtmp, sizeof(struct utmp)); 1172 close(i); 1173 } 1174#ifdef _CRAY 1175 signal(WJSIGNAL, sigjob); 1176#endif 1177 utmp_sig_notify(pid); 1178# endif /* PARENT_DOES_UTMP */ 1179 } else { 1180 getptyslave(); 1181#if defined(DCE) 1182 /* if we authenticated via K5, try and join the PAG */ 1183 kerberos5_dfspag(); 1184#endif 1185 start_login(host, autologin, autoname); 1186 /*NOTREACHED*/ 1187 } 1188} 1189 1190char *envinit[3]; 1191extern char **environ; 1192 1193void 1194init_env(void) 1195{ 1196 char **envp; 1197 1198 envp = envinit; 1199 if ((*envp = getenv("TZ"))) 1200 *envp++ -= 3; 1201#if defined(_CRAY) || defined(__hpux) 1202 else 1203 *envp++ = "TZ=GMT0"; 1204#endif 1205 *envp = 0; 1206 environ = envinit; 1207} 1208 1209/* 1210 * scrub_env() 1211 * 1212 * We only accept the environment variables listed below. 1213 */ 1214 1215static void 1216scrub_env(void) 1217{ 1218 static const char *reject[] = { 1219 "TERMCAP=/", 1220 NULL 1221 }; 1222 1223 static const char *accept[] = { 1224 "XAUTH=", "XAUTHORITY=", "DISPLAY=", 1225 "TERM=", 1226 "EDITOR=", 1227 "PAGER=", 1228 "PRINTER=", 1229 "LOGNAME=", 1230 "POSIXLY_CORRECT=", 1231 "TERMCAP=", 1232 NULL 1233 }; 1234 1235 char **cpp, **cpp2; 1236 const char **p; 1237 1238 for (cpp2 = cpp = environ; *cpp; cpp++) { 1239 int reject_it = 0; 1240 1241 for(p = reject; *p; p++) 1242 if(strncmp(*cpp, *p, strlen(*p)) == 0) { 1243 reject_it = 1; 1244 break; 1245 } 1246 if (reject_it) 1247 continue; 1248 1249 for(p = accept; *p; p++) 1250 if(strncmp(*cpp, *p, strlen(*p)) == 0) 1251 break; 1252 if(*p != NULL) 1253 *cpp2++ = *cpp; 1254 } 1255 *cpp2 = NULL; 1256} 1257 1258 1259struct arg_val { 1260 int size; 1261 int argc; 1262 const char **argv; 1263}; 1264 1265static void addarg(struct arg_val*, const char*); 1266 1267/* 1268 * start_login(host) 1269 * 1270 * Assuming that we are now running as a child processes, this 1271 * function will turn us into the login process. 1272 */ 1273 1274void 1275start_login(const char *host, int autologin, char *name) 1276{ 1277 struct arg_val argv; 1278 char *user; 1279 int save_errno; 1280 1281#ifdef HAVE_UTMPX_H 1282 int pid = getpid(); 1283 struct utmpx utmpx; 1284 char *clean_tty; 1285 1286 /* 1287 * Create utmp entry for child 1288 */ 1289 1290 clean_tty = clean_ttyname(line); 1291 memset(&utmpx, 0, sizeof(utmpx)); 1292 strncpy(utmpx.ut_user, ".telnet", sizeof(utmpx.ut_user)); 1293 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line)); 1294#ifdef HAVE_STRUCT_UTMP_UT_ID 1295 strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id)); 1296#endif 1297 utmpx.ut_pid = pid; 1298 1299 utmpx.ut_type = LOGIN_PROCESS; 1300 1301 gettimeofday (&utmpx.ut_tv, NULL); 1302 if (pututxline(&utmpx) == NULL) 1303 fatal(net, "pututxline failed"); 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\n", new_login); 1377 fatalperror_errno(net, new_login, save_errno); 1378 /*NOTREACHED*/ 1379} 1380 1381static void 1382addarg(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 argv->argv[argv->argc++] = val; 1391 argv->argv[argv->argc] = NULL; 1392} 1393 1394 1395/* 1396 * rmut() 1397 * 1398 * This is the function called by cleanup() to 1399 * remove the utmp entry for this person. 1400 */ 1401 1402#ifdef HAVE_UTMPX_H 1403static void 1404rmut(void) 1405{ 1406 struct utmpx utmpx, *non_save_utxp; 1407 char *clean_tty = clean_ttyname(line); 1408 1409 /* 1410 * This updates the utmpx and utmp entries and make a wtmp/x entry 1411 */ 1412 1413 setutxent(); 1414 memset(&utmpx, 0, sizeof(utmpx)); 1415 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line)); 1416 utmpx.ut_type = LOGIN_PROCESS; 1417 non_save_utxp = getutxline(&utmpx); 1418 if (non_save_utxp) { 1419 struct utmpx *utxp; 1420 char user0; 1421 1422 utxp = malloc(sizeof(struct utmpx)); 1423 *utxp = *non_save_utxp; 1424 user0 = utxp->ut_user[0]; 1425 utxp->ut_user[0] = '\0'; 1426 utxp->ut_type = DEAD_PROCESS; 1427#ifdef HAVE_STRUCT_UTMPX_UT_EXIT 1428#ifdef _STRUCT___EXIT_STATUS 1429 utxp->ut_exit.__e_termination = 0; 1430 utxp->ut_exit.__e_exit = 0; 1431#elif defined(__osf__) /* XXX */ 1432 utxp->ut_exit.ut_termination = 0; 1433 utxp->ut_exit.ut_exit = 0; 1434#else 1435 utxp->ut_exit.e_termination = 0; 1436 utxp->ut_exit.e_exit = 0; 1437#endif 1438#endif 1439 gettimeofday(&utxp->ut_tv, NULL); 1440 pututxline(utxp); 1441#ifdef WTMPX_FILE 1442 utxp->ut_user[0] = user0; 1443 updwtmpx(WTMPX_FILE, utxp); 1444#elif defined(WTMP_FILE) 1445 /* This is a strange system with a utmpx and a wtmp! */ 1446 { 1447 int f = open(wtmpf, O_WRONLY|O_APPEND); 1448 struct utmp wtmp; 1449 if (f >= 0) { 1450 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line)); 1451 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name)); 1452#ifdef HAVE_STRUCT_UTMP_UT_HOST 1453 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host)); 1454#endif 1455 wtmp.ut_time = time(NULL); 1456 write(f, &wtmp, sizeof(wtmp)); 1457 close(f); 1458 } 1459 } 1460#endif 1461 free (utxp); 1462 } 1463 endutxent(); 1464} /* end of rmut */ 1465#endif 1466 1467#if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43 1468static void 1469rmut(void) 1470{ 1471 int f; 1472 int found = 0; 1473 struct utmp *u, *utmp; 1474 int nutmp; 1475 struct stat statbf; 1476 char *clean_tty = clean_ttyname(line); 1477 1478 f = open(utmpf, O_RDWR); 1479 if (f >= 0) { 1480 fstat(f, &statbf); 1481 utmp = (struct utmp *)malloc((unsigned)statbf.st_size); 1482 if (!utmp) 1483 syslog(LOG_ERR, "utmp malloc failed"); 1484 if (statbf.st_size && utmp) { 1485 nutmp = read(f, utmp, (int)statbf.st_size); 1486 nutmp /= sizeof(struct utmp); 1487 1488 for (u = utmp ; u < &utmp[nutmp] ; u++) { 1489 if (strncmp(u->ut_line, 1490 clean_tty, 1491 sizeof(u->ut_line)) || 1492 u->ut_name[0]==0) 1493 continue; 1494 lseek(f, ((long)u)-((long)utmp), L_SET); 1495 strncpy(u->ut_name, "", sizeof(u->ut_name)); 1496#ifdef HAVE_STRUCT_UTMP_UT_HOST 1497 strncpy(u->ut_host, "", sizeof(u->ut_host)); 1498#endif 1499 u->ut_time = time(NULL); 1500 write(f, u, sizeof(wtmp)); 1501 found++; 1502 } 1503 } 1504 close(f); 1505 } 1506 if (found) { 1507 f = open(wtmpf, O_WRONLY|O_APPEND); 1508 if (f >= 0) { 1509 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line)); 1510 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name)); 1511#ifdef HAVE_STRUCT_UTMP_UT_HOST 1512 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host)); 1513#endif 1514 wtmp.ut_time = time(NULL); 1515 write(f, &wtmp, sizeof(wtmp)); 1516 close(f); 1517 } 1518 } 1519 chmod(line, 0666); 1520 chown(line, 0, 0); 1521 line[strlen("/dev/")] = 'p'; 1522 chmod(line, 0666); 1523 chown(line, 0, 0); 1524} /* end of rmut */ 1525#endif /* CRAY */ 1526 1527#if defined(__hpux) && !defined(HAVE_UTMPX_H) 1528static void 1529rmut (char *line) 1530{ 1531 struct utmp utmp; 1532 struct utmp *utptr; 1533 int fd; /* for /etc/wtmp */ 1534 1535 utmp.ut_type = USER_PROCESS; 1536 strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line)); 1537 setutent(); 1538 utptr = getutline(&utmp); 1539 /* write it out only if it exists */ 1540 if (utptr) { 1541 utptr->ut_type = DEAD_PROCESS; 1542 utptr->ut_time = time(NULL); 1543 pututline(utptr); 1544 /* set wtmp entry if wtmp file exists */ 1545 if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) { 1546 write(fd, utptr, sizeof(utmp)); 1547 close(fd); 1548 } 1549 } 1550 endutent(); 1551 1552 chmod(line, 0666); 1553 chown(line, 0, 0); 1554 line[14] = line[13]; 1555 line[13] = line[12]; 1556 line[8] = 'm'; 1557 line[9] = '/'; 1558 line[10] = 'p'; 1559 line[11] = 't'; 1560 line[12] = 'y'; 1561 chmod(line, 0666); 1562 chown(line, 0, 0); 1563} 1564#endif 1565 1566/* 1567 * cleanup() 1568 * 1569 * This is the routine to call when we are all through, to 1570 * clean up anything that needs to be cleaned up. 1571 */ 1572 1573#ifdef PARENT_DOES_UTMP 1574 1575void 1576cleanup(int sig) 1577{ 1578#ifdef _CRAY 1579 static int incleanup = 0; 1580 int t; 1581 int child_status; /* status of child process as returned by waitpid */ 1582 int flags = WNOHANG|WUNTRACED; 1583 1584 /* 1585 * 1: Pick up the zombie, if we are being called 1586 * as the signal handler. 1587 * 2: If we are a nested cleanup(), return. 1588 * 3: Try to clean up TMPDIR. 1589 * 4: Fill in utmp with shutdown of process. 1590 * 5: Close down the network and pty connections. 1591 * 6: Finish up the TMPDIR cleanup, if needed. 1592 */ 1593 if (sig == SIGCHLD) { 1594 while (waitpid(-1, &child_status, flags) > 0) 1595 ; /* VOID */ 1596 /* Check if the child process was stopped 1597 * rather than exited. We want cleanup only if 1598 * the child has died. 1599 */ 1600 if (WIFSTOPPED(child_status)) { 1601 return; 1602 } 1603 } 1604 t = sigblock(sigmask(SIGCHLD)); 1605 if (incleanup) { 1606 sigsetmask(t); 1607 return; 1608 } 1609 incleanup = 1; 1610 sigsetmask(t); 1611 1612 t = cleantmp(&wtmp); 1613 setutent(); /* just to make sure */ 1614#endif /* CRAY */ 1615 rmut(line); 1616 close(ourpty); 1617 shutdown(net, 2); 1618#ifdef _CRAY 1619 if (t == 0) 1620 cleantmp(&wtmp); 1621#endif /* CRAY */ 1622 exit(1); 1623} 1624 1625#else /* PARENT_DOES_UTMP */ 1626 1627void 1628cleanup(int sig) 1629{ 1630#if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP) 1631 rmut(); 1632#ifdef HAVE_VHANGUP 1633#ifndef __sgi 1634 vhangup(); /* XXX */ 1635#endif 1636#endif 1637#else 1638 char *p; 1639 1640 p = line + sizeof("/dev/") - 1; 1641 if (logout(p)) 1642 logwtmp(p, "", ""); 1643 chmod(line, 0666); 1644 chown(line, 0, 0); 1645 *p = 'p'; 1646 chmod(line, 0666); 1647 chown(line, 0, 0); 1648#endif 1649 shutdown(net, 2); 1650 exit(1); 1651} 1652 1653#endif /* PARENT_DOES_UTMP */ 1654 1655#ifdef PARENT_DOES_UTMP 1656/* 1657 * _utmp_sig_rcv 1658 * utmp_sig_init 1659 * utmp_sig_wait 1660 * These three functions are used to coordinate the handling of 1661 * the utmp file between the server and the soon-to-be-login shell. 1662 * The server actually creates the utmp structure, the child calls 1663 * utmp_sig_wait(), until the server calls utmp_sig_notify() and 1664 * signals the future-login shell to proceed. 1665 */ 1666static int caught=0; /* NZ when signal intercepted */ 1667static void (*func)(); /* address of previous handler */ 1668 1669void 1670_utmp_sig_rcv(sig) 1671 int sig; 1672{ 1673 caught = 1; 1674 signal(SIGUSR1, func); 1675} 1676 1677void 1678utmp_sig_init() 1679{ 1680 /* 1681 * register signal handler for UTMP creation 1682 */ 1683 if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1) 1684 fatalperror(net, "telnetd/signal"); 1685} 1686 1687void 1688utmp_sig_reset() 1689{ 1690 signal(SIGUSR1, func); /* reset handler to default */ 1691} 1692 1693# ifdef __hpux 1694# define sigoff() /* do nothing */ 1695# define sigon() /* do nothing */ 1696# endif 1697 1698void 1699utmp_sig_wait() 1700{ 1701 /* 1702 * Wait for parent to write our utmp entry. 1703 */ 1704 sigoff(); 1705 while (caught == 0) { 1706 pause(); /* wait until we get a signal (sigon) */ 1707 sigoff(); /* turn off signals while we check caught */ 1708 } 1709 sigon(); /* turn on signals again */ 1710} 1711 1712void 1713utmp_sig_notify(pid) 1714{ 1715 kill(pid, SIGUSR1); 1716} 1717 1718#ifdef _CRAY 1719static int gotsigjob = 0; 1720 1721 /*ARGSUSED*/ 1722void 1723sigjob(sig) 1724 int sig; 1725{ 1726 int jid; 1727 struct jobtemp *jp; 1728 1729 while ((jid = waitjob(NULL)) != -1) { 1730 if (jid == 0) { 1731 return; 1732 } 1733 gotsigjob++; 1734 jobend(jid, NULL, NULL); 1735 } 1736} 1737 1738/* 1739 * jid_getutid: 1740 * called by jobend() before calling cleantmp() 1741 * to find the correct $TMPDIR to cleanup. 1742 */ 1743 1744struct utmp * 1745jid_getutid(jid) 1746 int jid; 1747{ 1748 struct utmp *cur = NULL; 1749 1750 setutent(); /* just to make sure */ 1751 while (cur = getutent()) { 1752 if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) { 1753 return(cur); 1754 } 1755 } 1756 1757 return(0); 1758} 1759 1760/* 1761 * Clean up the TMPDIR that login created. 1762 * The first time this is called we pick up the info 1763 * from the utmp. If the job has already gone away, 1764 * then we'll clean up and be done. If not, then 1765 * when this is called the second time it will wait 1766 * for the signal that the job is done. 1767 */ 1768int 1769cleantmp(wtp) 1770 struct utmp *wtp; 1771{ 1772 struct utmp *utp; 1773 static int first = 1; 1774 int mask, omask, ret; 1775 extern struct utmp *getutid (const struct utmp *_Id); 1776 1777 1778 mask = sigmask(WJSIGNAL); 1779 1780 if (first == 0) { 1781 omask = sigblock(mask); 1782 while (gotsigjob == 0) 1783 sigpause(omask); 1784 return(1); 1785 } 1786 first = 0; 1787 setutent(); /* just to make sure */ 1788 1789 utp = getutid(wtp); 1790 if (utp == 0) { 1791 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); 1792 return(-1); 1793 } 1794 /* 1795 * Nothing to clean up if the user shell was never started. 1796 */ 1797 if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0) 1798 return(1); 1799 1800 /* 1801 * Block the WJSIGNAL while we are in jobend(). 1802 */ 1803 omask = sigblock(mask); 1804 ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user); 1805 sigsetmask(omask); 1806 return(ret); 1807} 1808 1809int 1810jobend(jid, path, user) 1811 int jid; 1812 char *path; 1813 char *user; 1814{ 1815 static int saved_jid = 0; 1816 static int pty_saved_jid = 0; 1817 static char saved_path[sizeof(wtmp.ut_tpath)+1]; 1818 static char saved_user[sizeof(wtmp.ut_user)+1]; 1819 1820 /* 1821 * this little piece of code comes into play 1822 * only when ptyreconnect is used to reconnect 1823 * to an previous session. 1824 * 1825 * this is the only time when the 1826 * "saved_jid != jid" code is executed. 1827 */ 1828 1829 if ( saved_jid && saved_jid != jid ) { 1830 if (!path) { /* called from signal handler */ 1831 pty_saved_jid = jid; 1832 } else { 1833 pty_saved_jid = saved_jid; 1834 } 1835 } 1836 1837 if (path) { 1838 strncpy(saved_path, path, sizeof(wtmp.ut_tpath)); 1839 strncpy(saved_user, user, sizeof(wtmp.ut_user)); 1840 saved_path[sizeof(saved_path)] = '\0'; 1841 saved_user[sizeof(saved_user)] = '\0'; 1842 } 1843 if (saved_jid == 0) { 1844 saved_jid = jid; 1845 return(0); 1846 } 1847 1848 /* if the jid has changed, get the correct entry from the utmp file */ 1849 1850 if ( saved_jid != jid ) { 1851 struct utmp *utp = NULL; 1852 struct utmp *jid_getutid(); 1853 1854 utp = jid_getutid(pty_saved_jid); 1855 1856 if (utp == 0) { 1857 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); 1858 return(-1); 1859 } 1860 1861 cleantmpdir(jid, utp->ut_tpath, utp->ut_user); 1862 return(1); 1863 } 1864 1865 cleantmpdir(jid, saved_path, saved_user); 1866 return(1); 1867} 1868 1869/* 1870 * Fork a child process to clean up the TMPDIR 1871 */ 1872cleantmpdir(jid, tpath, user) 1873 int jid; 1874 char *tpath; 1875 char *user; 1876{ 1877 switch(fork()) { 1878 case -1: 1879 syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n", 1880 tpath); 1881 break; 1882 case 0: 1883 execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0); 1884 syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n", 1885 tpath, CLEANTMPCMD); 1886 exit(1); 1887 default: 1888 /* 1889 * Forget about child. We will exit, and 1890 * /etc/init will pick it up. 1891 */ 1892 break; 1893 } 1894} 1895#endif /* CRAY */ 1896#endif /* defined(PARENT_DOES_UTMP) */ 1897