157416Smarkm/* 257416Smarkm * Copyright (c) 1989, 1993 357416Smarkm * The Regents of the University of California. All rights reserved. 457416Smarkm * 557416Smarkm * Redistribution and use in source and binary forms, with or without 657416Smarkm * modification, are permitted provided that the following conditions 757416Smarkm * are met: 857416Smarkm * 1. Redistributions of source code must retain the above copyright 957416Smarkm * notice, this list of conditions and the following disclaimer. 1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1157416Smarkm * notice, this list of conditions and the following disclaimer in the 1257416Smarkm * documentation and/or other materials provided with the distribution. 1357416Smarkm * 3. All advertising materials mentioning features or use of this software 1457416Smarkm * must display the following acknowledgement: 1557416Smarkm * This product includes software developed by the University of 1657416Smarkm * California, Berkeley and its contributors. 1757416Smarkm * 4. Neither the name of the University nor the names of its contributors 1857416Smarkm * may be used to endorse or promote products derived from this software 1957416Smarkm * without specific prior written permission. 2057416Smarkm * 2157416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2257416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2357416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2457416Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2557416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2657416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2757416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2857416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2957416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3057416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3157416Smarkm * SUCH DAMAGE. 3257416Smarkm */ 3357416Smarkm 3457416Smarkm#include "telnetd.h" 3557416Smarkm 36233294SstasRCSID("$Id$"); 3757416Smarkm 3857416Smarkm#if defined(_CRAY) || (defined(__hpux) && !defined(HAVE_UTMPX_H)) 3957416Smarkm# define PARENT_DOES_UTMP 4057416Smarkm#endif 4157416Smarkm 4257416Smarkm#ifdef HAVE_UTMP_H 4357416Smarkm#include <utmp.h> 4457416Smarkm#endif 4557416Smarkm 4657416Smarkm#ifdef HAVE_UTMPX_H 4757416Smarkm#include <utmpx.h> 4857416Smarkm#endif 4957416Smarkm 5057416Smarkm#ifdef HAVE_UTMPX_H 5157416Smarkmstruct utmpx wtmp; 5257416Smarkm#elif defined(HAVE_UTMP_H) 5357416Smarkmstruct utmp wtmp; 5457416Smarkm#endif /* HAVE_UTMPX_H */ 5557416Smarkm 5657416Smarkm#ifdef HAVE_STRUCT_UTMP_UT_HOST 5757416Smarkmint utmp_len = sizeof(wtmp.ut_host); 5857416Smarkm#else 5957416Smarkmint utmp_len = MaxHostNameLen; 6057416Smarkm#endif 6157416Smarkm 6257416Smarkm#ifndef UTMP_FILE 6357416Smarkm#ifdef _PATH_UTMP 6457416Smarkm#define UTMP_FILE _PATH_UTMP 6557416Smarkm#else 6657416Smarkm#define UTMP_FILE "/etc/utmp" 6757416Smarkm#endif 6857416Smarkm#endif 6957416Smarkm 70233294Sstas/* really, mac os uses wtmpx (or asl) */ 71233294Sstas#ifdef __APPLE__ 72233294Sstas#undef _PATH_WTMP 73233294Sstas#endif 74233294Sstas 7557416Smarkm#if !defined(WTMP_FILE) && defined(_PATH_WTMP) 7657416Smarkm#define WTMP_FILE _PATH_WTMP 7757416Smarkm#endif 7857416Smarkm 7957416Smarkm#ifndef PARENT_DOES_UTMP 8057416Smarkm#ifdef WTMP_FILE 8157416Smarkmchar wtmpf[] = WTMP_FILE; 8257416Smarkm#else 8357416Smarkmchar wtmpf[] = "/usr/adm/wtmp"; 8457416Smarkm#endif 8557416Smarkmchar utmpf[] = UTMP_FILE; 8657416Smarkm#else /* PARENT_DOES_UTMP */ 8757416Smarkm#ifdef WTMP_FILE 8857416Smarkmchar wtmpf[] = WTMP_FILE; 8957416Smarkm#else 9057416Smarkmchar wtmpf[] = "/etc/wtmp"; 9157416Smarkm#endif 9257416Smarkm#endif /* PARENT_DOES_UTMP */ 9357416Smarkm 9457416Smarkm#ifdef HAVE_TMPDIR_H 9557416Smarkm#include <tmpdir.h> 9657416Smarkm#endif /* CRAY */ 9757416Smarkm 9857416Smarkm#if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY) 9957416Smarkm#include <sys/tty.h> 10057416Smarkm#endif 10157416Smarkm#ifdef t_erase 10257416Smarkm#undef t_erase 10357416Smarkm#undef t_kill 10457416Smarkm#undef t_intrc 10557416Smarkm#undef t_quitc 10657416Smarkm#undef t_startc 10757416Smarkm#undef t_stopc 10857416Smarkm#undef t_eofc 10957416Smarkm#undef t_brkc 11057416Smarkm#undef t_suspc 11157416Smarkm#undef t_dsuspc 11257416Smarkm#undef t_rprntc 11357416Smarkm#undef t_flushc 11457416Smarkm#undef t_werasc 11557416Smarkm#undef t_lnextc 11657416Smarkm#endif 11757416Smarkm 11857416Smarkm#ifdef HAVE_TERMIOS_H 11957416Smarkm#include <termios.h> 12057416Smarkm#else 12157416Smarkm#ifdef HAVE_TERMIO_H 12257416Smarkm#include <termio.h> 12357416Smarkm#endif 12457416Smarkm#endif 12557416Smarkm 12657416Smarkm#ifdef HAVE_UTIL_H 12757416Smarkm#include <util.h> 12857416Smarkm#endif 12990926Snectar#ifdef HAVE_LIBUTIL_H 13090926Snectar#include <libutil.h> 13190926Snectar#endif 13257416Smarkm 13357416Smarkm# ifndef TCSANOW 13457416Smarkm# ifdef TCSETS 13557416Smarkm# define TCSANOW TCSETS 13657416Smarkm# define TCSADRAIN TCSETSW 13757416Smarkm# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) 13857416Smarkm# else 13957416Smarkm# ifdef TCSETA 14057416Smarkm# define TCSANOW TCSETA 14157416Smarkm# define TCSADRAIN TCSETAW 14257416Smarkm# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) 14357416Smarkm# else 14457416Smarkm# define TCSANOW TIOCSETA 14557416Smarkm# define TCSADRAIN TIOCSETAW 14657416Smarkm# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) 14757416Smarkm# endif 14857416Smarkm# endif 14957416Smarkm# define tcsetattr(f, a, t) ioctl(f, a, t) 15057416Smarkm# define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ 15157416Smarkm(tp)->c_cflag |= (val) 15257416Smarkm# define cfgetospeed(tp) ((tp)->c_cflag & CBAUD) 15357416Smarkm# ifdef CIBAUD 15457416Smarkm# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \ 15557416Smarkm (tp)->c_cflag |= ((val)<<IBSHIFT) 15657416Smarkm# define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT) 15757416Smarkm# else 15857416Smarkm# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ 15957416Smarkm (tp)->c_cflag |= (val) 16057416Smarkm# define cfgetispeed(tp) ((tp)->c_cflag & CBAUD) 16157416Smarkm# endif 16257416Smarkm# endif /* TCSANOW */ 16357416Smarkm struct termios termbuf, termbuf2; /* pty control structure */ 16457416Smarkm# ifdef STREAMSPTY 16557416Smarkm static int ttyfd = -1; 16657416Smarkm int really_stream = 0; 167233294Sstas# else 168233294Sstas#define really_stream 0 16957416Smarkm# endif 17057416Smarkm 17157416Smarkm const char *new_login = _PATH_LOGIN; 17257416Smarkm 17357416Smarkm/* 17457416Smarkm * init_termbuf() 17557416Smarkm * copy_termbuf(cp) 17657416Smarkm * set_termbuf() 17757416Smarkm * 17857416Smarkm * These three routines are used to get and set the "termbuf" structure 17957416Smarkm * to and from the kernel. init_termbuf() gets the current settings. 18057416Smarkm * copy_termbuf() hands in a new "termbuf" to write to the kernel, and 18157416Smarkm * set_termbuf() writes the structure into the kernel. 18257416Smarkm */ 18357416Smarkm 18457416Smarkm void 18557416Smarkm init_termbuf(void) 18657416Smarkm{ 18757416Smarkm# ifdef STREAMSPTY 18857416Smarkm if (really_stream) 18957416Smarkm tcgetattr(ttyfd, &termbuf); 19057416Smarkm else 19157416Smarkm# endif 19257416Smarkm tcgetattr(ourpty, &termbuf); 19357416Smarkm termbuf2 = termbuf; 19457416Smarkm} 19557416Smarkm 19657416Smarkmvoid 19757416Smarkmset_termbuf(void) 19857416Smarkm{ 19957416Smarkm /* 20057416Smarkm * Only make the necessary changes. 20157416Smarkm */ 202178825Sdfr if (memcmp(&termbuf, &termbuf2, sizeof(termbuf))) { 20357416Smarkm# ifdef STREAMSPTY 20457416Smarkm if (really_stream) 20557416Smarkm tcsetattr(ttyfd, TCSANOW, &termbuf); 20657416Smarkm else 20757416Smarkm# endif 20857416Smarkm tcsetattr(ourpty, TCSANOW, &termbuf); 209178825Sdfr } 21057416Smarkm} 21157416Smarkm 21257416Smarkm 21357416Smarkm/* 21457416Smarkm * spcset(func, valp, valpp) 21557416Smarkm * 21657416Smarkm * This function takes various special characters (func), and 21757416Smarkm * sets *valp to the current value of that character, and 21857416Smarkm * *valpp to point to where in the "termbuf" structure that 21957416Smarkm * value is kept. 22057416Smarkm * 22157416Smarkm * It returns the SLC_ level of support for this function. 22257416Smarkm */ 22357416Smarkm 22457416Smarkm 22557416Smarkmint 22657416Smarkmspcset(int func, cc_t *valp, cc_t **valpp) 22757416Smarkm{ 22857416Smarkm 22957416Smarkm#define setval(a, b) *valp = termbuf.c_cc[a]; \ 23057416Smarkm *valpp = &termbuf.c_cc[a]; \ 23157416Smarkm return(b); 23257416Smarkm#define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT); 23357416Smarkm 23457416Smarkm switch(func) { 23557416Smarkm case SLC_EOF: 23657416Smarkm setval(VEOF, SLC_VARIABLE); 23757416Smarkm case SLC_EC: 23857416Smarkm setval(VERASE, SLC_VARIABLE); 23957416Smarkm case SLC_EL: 24057416Smarkm setval(VKILL, SLC_VARIABLE); 24157416Smarkm case SLC_IP: 24257416Smarkm setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 24357416Smarkm case SLC_ABORT: 24457416Smarkm setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 24557416Smarkm case SLC_XON: 24657416Smarkm#ifdef VSTART 24757416Smarkm setval(VSTART, SLC_VARIABLE); 24857416Smarkm#else 24957416Smarkm defval(0x13); 25057416Smarkm#endif 25157416Smarkm case SLC_XOFF: 25257416Smarkm#ifdef VSTOP 25357416Smarkm setval(VSTOP, SLC_VARIABLE); 25457416Smarkm#else 25557416Smarkm defval(0x11); 25657416Smarkm#endif 25757416Smarkm case SLC_EW: 25857416Smarkm#ifdef VWERASE 25957416Smarkm setval(VWERASE, SLC_VARIABLE); 26057416Smarkm#else 26157416Smarkm defval(0); 26257416Smarkm#endif 26357416Smarkm case SLC_RP: 26457416Smarkm#ifdef VREPRINT 26557416Smarkm setval(VREPRINT, SLC_VARIABLE); 26657416Smarkm#else 26757416Smarkm defval(0); 26857416Smarkm#endif 26957416Smarkm case SLC_LNEXT: 27057416Smarkm#ifdef VLNEXT 27157416Smarkm setval(VLNEXT, SLC_VARIABLE); 27257416Smarkm#else 27357416Smarkm defval(0); 27457416Smarkm#endif 27557416Smarkm case SLC_AO: 27657416Smarkm#if !defined(VDISCARD) && defined(VFLUSHO) 27757416Smarkm# define VDISCARD VFLUSHO 27857416Smarkm#endif 27957416Smarkm#ifdef VDISCARD 28057416Smarkm setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT); 28157416Smarkm#else 28257416Smarkm defval(0); 28357416Smarkm#endif 28457416Smarkm case SLC_SUSP: 28557416Smarkm#ifdef VSUSP 28657416Smarkm setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); 28757416Smarkm#else 28857416Smarkm defval(0); 28957416Smarkm#endif 29057416Smarkm#ifdef VEOL 29157416Smarkm case SLC_FORW1: 29257416Smarkm setval(VEOL, SLC_VARIABLE); 29357416Smarkm#endif 29457416Smarkm#ifdef VEOL2 29557416Smarkm case SLC_FORW2: 29657416Smarkm setval(VEOL2, SLC_VARIABLE); 29757416Smarkm#endif 29857416Smarkm case SLC_AYT: 29957416Smarkm#ifdef VSTATUS 30057416Smarkm setval(VSTATUS, SLC_VARIABLE); 30157416Smarkm#else 30257416Smarkm defval(0); 30357416Smarkm#endif 30457416Smarkm 30557416Smarkm case SLC_BRK: 30657416Smarkm case SLC_SYNCH: 30757416Smarkm case SLC_EOR: 30857416Smarkm defval(0); 30957416Smarkm 31057416Smarkm default: 31157416Smarkm *valp = 0; 31257416Smarkm *valpp = 0; 31357416Smarkm return(SLC_NOSUPPORT); 31457416Smarkm } 31557416Smarkm} 31657416Smarkm 31757416Smarkm#ifdef _CRAY 31857416Smarkm/* 31957416Smarkm * getnpty() 32057416Smarkm * 32157416Smarkm * Return the number of pty's configured into the system. 32257416Smarkm */ 32357416Smarkmint 32457416Smarkmgetnpty() 32557416Smarkm{ 32657416Smarkm#ifdef _SC_CRAY_NPTY 32757416Smarkm int numptys; 32857416Smarkm 32957416Smarkm if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1) 33057416Smarkm return numptys; 33157416Smarkm else 33257416Smarkm#endif /* _SC_CRAY_NPTY */ 33357416Smarkm return 128; 33457416Smarkm} 33557416Smarkm#endif /* CRAY */ 33657416Smarkm 33757416Smarkm/* 33857416Smarkm * getpty() 33957416Smarkm * 34057416Smarkm * Allocate a pty. As a side effect, the external character 34157416Smarkm * array "line" contains the name of the slave side. 34257416Smarkm * 34357416Smarkm * Returns the file descriptor of the opened pty. 34457416Smarkm */ 34557416Smarkm 346178825Sdfrstatic int ptyslavefd = -1; 347178825Sdfr 34857416Smarkmstatic char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 34957416Smarkmchar *line = Xline; 35057416Smarkm 35157416Smarkm#ifdef _CRAY 35257416Smarkmchar myline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 35357416Smarkm#endif /* CRAY */ 35457416Smarkm 35557416Smarkm#if !defined(HAVE_PTSNAME) && defined(STREAMSPTY) 35657416Smarkmstatic char *ptsname(int fd) 35757416Smarkm{ 35857416Smarkm#ifdef HAVE_TTYNAME 35957416Smarkm return ttyname(fd); 36057416Smarkm#else 36157416Smarkm return NULL; 36257416Smarkm#endif 36357416Smarkm} 36457416Smarkm#endif 36557416Smarkm 36657416Smarkmint getpty(int *ptynum) 36757416Smarkm{ 368178825Sdfr#if defined(HAVE_OPENPTY) || defined(__linux) || defined(__osf__) /* XXX */ 369178825Sdfr { 370178825Sdfr int master; 371178825Sdfr int slave; 372178825Sdfr if(openpty(&master, &slave, line, 0, 0) == 0){ 373178825Sdfr ptyslavefd = slave; 374178825Sdfr return master; 375178825Sdfr } 37657416Smarkm } 377178825Sdfr#endif /* HAVE_OPENPTY .... */ 37857416Smarkm#ifdef HAVE__GETPTY 379178825Sdfr { 380178825Sdfr int master; 381178825Sdfr char *p; 382178825Sdfr p = _getpty(&master, O_RDWR, 0600, 1); 383178825Sdfr if(p == NULL) 384178825Sdfr return -1; 385178825Sdfr strlcpy(line, p, sizeof(Xline)); 38657416Smarkm return master; 38757416Smarkm } 388178825Sdfr#endif 389233294Sstas 39057416Smarkm#ifdef STREAMSPTY 391178825Sdfr { 392233294Sstas char *clone[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm", 393178825Sdfr "/dev/ptym/clone", 0 }; 394233294Sstas 395178825Sdfr char **q; 396178825Sdfr int p; 397178825Sdfr for(q=clone; *q; q++){ 398178825Sdfr p=open(*q, O_RDWR); 399178825Sdfr if(p >= 0){ 40057416Smarkm#ifdef HAVE_GRANTPT 401178825Sdfr grantpt(p); 40257416Smarkm#endif 40357416Smarkm#ifdef HAVE_UNLOCKPT 404178825Sdfr unlockpt(p); 40557416Smarkm#endif 406178825Sdfr strlcpy(line, ptsname(p), sizeof(Xline)); 407178825Sdfr really_stream = 1; 408178825Sdfr return p; 409178825Sdfr } 41057416Smarkm } 41157416Smarkm } 41257416Smarkm#endif /* STREAMSPTY */ 41357416Smarkm#ifndef _CRAY 414178825Sdfr { 415178825Sdfr int p; 416178825Sdfr char *cp, *p1, *p2; 417178825Sdfr int i; 418233294Sstas 41957416Smarkm#ifndef __hpux 420178825Sdfr snprintf(line, sizeof(Xline), "/dev/ptyXX"); 421178825Sdfr p1 = &line[8]; 422178825Sdfr p2 = &line[9]; 42357416Smarkm#else 424178825Sdfr snprintf(line, sizeof(Xline), "/dev/ptym/ptyXX"); 425178825Sdfr p1 = &line[13]; 426178825Sdfr p2 = &line[14]; 42757416Smarkm#endif 428233294Sstas 429233294Sstas 430178825Sdfr for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) { 431178825Sdfr struct stat stb; 432233294Sstas 433178825Sdfr *p1 = *cp; 434178825Sdfr *p2 = '0'; 435178825Sdfr /* 436178825Sdfr * This stat() check is just to keep us from 437178825Sdfr * looping through all 256 combinations if there 438178825Sdfr * aren't that many ptys available. 439178825Sdfr */ 440178825Sdfr if (stat(line, &stb) < 0) 441178825Sdfr break; 442178825Sdfr for (i = 0; i < 16; i++) { 443178825Sdfr *p2 = "0123456789abcdef"[i]; 444178825Sdfr p = open(line, O_RDWR); 445178825Sdfr if (p > 0) { 446178825Sdfr#if SunOS == 40 447178825Sdfr int dummy; 448178825Sdfr#endif 449233294Sstas 45057416Smarkm#ifndef __hpux 451178825Sdfr line[5] = 't'; 45257416Smarkm#else 453178825Sdfr for (p1 = &line[8]; *p1; p1++) 454178825Sdfr *p1 = *(p1+1); 455178825Sdfr line[9] = 't'; 45657416Smarkm#endif 457178825Sdfr chown(line, 0, 0); 458178825Sdfr chmod(line, 0600); 45957416Smarkm#if SunOS == 40 460178825Sdfr if (ioctl(p, TIOCGPGRP, &dummy) == 0 461178825Sdfr || errno != EIO) { 462178825Sdfr chmod(line, 0666); 463178825Sdfr close(p); 464178825Sdfr line[5] = 'p'; 465178825Sdfr } else 46657416Smarkm#endif /* SunOS == 40 */ 467178825Sdfr return(p); 468178825Sdfr } 46957416Smarkm } 47057416Smarkm } 47157416Smarkm } 47257416Smarkm#else /* CRAY */ 473178825Sdfr { 474178825Sdfr extern lowpty, highpty; 475178825Sdfr struct stat sb; 476178825Sdfr int p; 477233294Sstas 478178825Sdfr for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) { 479178825Sdfr snprintf(myline, sizeof(myline), "/dev/pty/%03d", *ptynum); 48057416Smarkm p = open(myline, 2); 48157416Smarkm if (p < 0) 48257416Smarkm continue; 483178825Sdfr snprintf(line, sizeof(Xline), "/dev/ttyp%03d", *ptynum); 484178825Sdfr /* 485178825Sdfr * Here are some shenanigans to make sure that there 486178825Sdfr * are no listeners lurking on the line. 487178825Sdfr */ 488178825Sdfr if(stat(line, &sb) < 0) { 489178825Sdfr close(p); 490178825Sdfr continue; 491178825Sdfr } 492178825Sdfr if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) { 493178825Sdfr chown(line, 0, 0); 494178825Sdfr chmod(line, 0600); 495178825Sdfr close(p); 496178825Sdfr p = open(myline, 2); 497178825Sdfr if (p < 0) 498178825Sdfr continue; 499178825Sdfr } 500178825Sdfr /* 501178825Sdfr * Now it should be safe...check for accessability. 502178825Sdfr */ 503178825Sdfr if (access(line, 6) == 0) 504178825Sdfr return(p); 505178825Sdfr else { 506178825Sdfr /* no tty side to pty so skip it */ 507178825Sdfr close(p); 508178825Sdfr } 50957416Smarkm } 51057416Smarkm } 51157416Smarkm#endif /* CRAY */ 51257416Smarkm return(-1); 51357416Smarkm} 51457416Smarkm 51557416Smarkm 51657416Smarkmint 51757416Smarkmtty_isecho(void) 51857416Smarkm{ 51957416Smarkm return (termbuf.c_lflag & ECHO); 52057416Smarkm} 52157416Smarkm 52257416Smarkmint 52357416Smarkmtty_flowmode(void) 52457416Smarkm{ 52557416Smarkm return((termbuf.c_iflag & IXON) ? 1 : 0); 52657416Smarkm} 52757416Smarkm 52857416Smarkmint 52957416Smarkmtty_restartany(void) 53057416Smarkm{ 53157416Smarkm return((termbuf.c_iflag & IXANY) ? 1 : 0); 53257416Smarkm} 53357416Smarkm 53457416Smarkmvoid 53557416Smarkmtty_setecho(int on) 53657416Smarkm{ 53757416Smarkm if (on) 53857416Smarkm termbuf.c_lflag |= ECHO; 53957416Smarkm else 54057416Smarkm termbuf.c_lflag &= ~ECHO; 54157416Smarkm} 54257416Smarkm 54357416Smarkmint 54457416Smarkmtty_israw(void) 54557416Smarkm{ 54657416Smarkm return(!(termbuf.c_lflag & ICANON)); 54757416Smarkm} 54857416Smarkm 54957416Smarkmvoid 55057416Smarkmtty_binaryin(int on) 55157416Smarkm{ 55257416Smarkm if (on) { 55357416Smarkm termbuf.c_iflag &= ~ISTRIP; 55457416Smarkm } else { 55557416Smarkm termbuf.c_iflag |= ISTRIP; 55657416Smarkm } 55757416Smarkm} 55857416Smarkm 55957416Smarkmvoid 56057416Smarkmtty_binaryout(int on) 56157416Smarkm{ 56257416Smarkm if (on) { 56357416Smarkm termbuf.c_cflag &= ~(CSIZE|PARENB); 56457416Smarkm termbuf.c_cflag |= CS8; 56557416Smarkm termbuf.c_oflag &= ~OPOST; 56657416Smarkm } else { 56757416Smarkm termbuf.c_cflag &= ~CSIZE; 56857416Smarkm termbuf.c_cflag |= CS7|PARENB; 56957416Smarkm termbuf.c_oflag |= OPOST; 57057416Smarkm } 57157416Smarkm} 57257416Smarkm 57357416Smarkmint 57457416Smarkmtty_isbinaryin(void) 57557416Smarkm{ 57657416Smarkm return(!(termbuf.c_iflag & ISTRIP)); 57757416Smarkm} 57857416Smarkm 57957416Smarkmint 58057416Smarkmtty_isbinaryout(void) 58157416Smarkm{ 58257416Smarkm return(!(termbuf.c_oflag&OPOST)); 58357416Smarkm} 58457416Smarkm 58557416Smarkm 58657416Smarkmint 58757416Smarkmtty_issofttab(void) 58857416Smarkm{ 58957416Smarkm# ifdef OXTABS 59057416Smarkm return (termbuf.c_oflag & OXTABS); 59157416Smarkm# endif 59257416Smarkm# ifdef TABDLY 59357416Smarkm return ((termbuf.c_oflag & TABDLY) == TAB3); 59457416Smarkm# endif 59557416Smarkm} 59657416Smarkm 59757416Smarkmvoid 59857416Smarkmtty_setsofttab(int on) 59957416Smarkm{ 60057416Smarkm if (on) { 60157416Smarkm# ifdef OXTABS 60257416Smarkm termbuf.c_oflag |= OXTABS; 60357416Smarkm# endif 60457416Smarkm# ifdef TABDLY 60557416Smarkm termbuf.c_oflag &= ~TABDLY; 60657416Smarkm termbuf.c_oflag |= TAB3; 60757416Smarkm# endif 60857416Smarkm } else { 60957416Smarkm# ifdef OXTABS 61057416Smarkm termbuf.c_oflag &= ~OXTABS; 61157416Smarkm# endif 61257416Smarkm# ifdef TABDLY 61357416Smarkm termbuf.c_oflag &= ~TABDLY; 61457416Smarkm termbuf.c_oflag |= TAB0; 61557416Smarkm# endif 61657416Smarkm } 61757416Smarkm} 61857416Smarkm 61957416Smarkmint 62057416Smarkmtty_islitecho(void) 62157416Smarkm{ 62257416Smarkm# ifdef ECHOCTL 62357416Smarkm return (!(termbuf.c_lflag & ECHOCTL)); 62457416Smarkm# endif 62557416Smarkm# ifdef TCTLECH 62657416Smarkm return (!(termbuf.c_lflag & TCTLECH)); 62757416Smarkm# endif 62857416Smarkm# if !defined(ECHOCTL) && !defined(TCTLECH) 62957416Smarkm return (0); /* assumes ctl chars are echoed '^x' */ 63057416Smarkm# endif 63157416Smarkm} 63257416Smarkm 63357416Smarkmvoid 63457416Smarkmtty_setlitecho(int on) 63557416Smarkm{ 63657416Smarkm# ifdef ECHOCTL 63757416Smarkm if (on) 63857416Smarkm termbuf.c_lflag &= ~ECHOCTL; 63957416Smarkm else 64057416Smarkm termbuf.c_lflag |= ECHOCTL; 64157416Smarkm# endif 64257416Smarkm# ifdef TCTLECH 64357416Smarkm if (on) 64457416Smarkm termbuf.c_lflag &= ~TCTLECH; 64557416Smarkm else 64657416Smarkm termbuf.c_lflag |= TCTLECH; 64757416Smarkm# endif 64857416Smarkm} 64957416Smarkm 65057416Smarkmint 65157416Smarkmtty_iscrnl(void) 65257416Smarkm{ 65357416Smarkm return (termbuf.c_iflag & ICRNL); 65457416Smarkm} 65557416Smarkm 65657416Smarkm/* 65757416Smarkm * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). 65857416Smarkm */ 65957416Smarkm#if B4800 != 4800 66057416Smarkm#define DECODE_BAUD 66157416Smarkm#endif 66257416Smarkm 66357416Smarkm#ifdef DECODE_BAUD 66457416Smarkm 66557416Smarkm/* 66657416Smarkm * A table of available terminal speeds 66757416Smarkm */ 66857416Smarkmstruct termspeeds { 66957416Smarkm int speed; 67057416Smarkm int value; 67157416Smarkm} termspeeds[] = { 67257416Smarkm { 0, B0 }, { 50, B50 }, { 75, B75 }, 67357416Smarkm { 110, B110 }, { 134, B134 }, { 150, B150 }, 67457416Smarkm { 200, B200 }, { 300, B300 }, { 600, B600 }, 67557416Smarkm { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 67657416Smarkm { 4800, B4800 }, 67757416Smarkm#ifdef B7200 67857416Smarkm { 7200, B7200 }, 67957416Smarkm#endif 68057416Smarkm { 9600, B9600 }, 68157416Smarkm#ifdef B14400 68257416Smarkm { 14400, B14400 }, 68357416Smarkm#endif 68457416Smarkm#ifdef B19200 68557416Smarkm { 19200, B19200 }, 68657416Smarkm#endif 68757416Smarkm#ifdef B28800 68857416Smarkm { 28800, B28800 }, 68957416Smarkm#endif 69057416Smarkm#ifdef B38400 69157416Smarkm { 38400, B38400 }, 69257416Smarkm#endif 69357416Smarkm#ifdef B57600 69457416Smarkm { 57600, B57600 }, 69557416Smarkm#endif 69657416Smarkm#ifdef B115200 69757416Smarkm { 115200, B115200 }, 69857416Smarkm#endif 69957416Smarkm#ifdef B230400 70057416Smarkm { 230400, B230400 }, 70157416Smarkm#endif 70257416Smarkm { -1, 0 } 70357416Smarkm}; 70457416Smarkm#endif /* DECODE_BUAD */ 70557416Smarkm 70657416Smarkmvoid 70757416Smarkmtty_tspeed(int val) 70857416Smarkm{ 70957416Smarkm#ifdef DECODE_BAUD 71057416Smarkm struct termspeeds *tp; 71157416Smarkm 71257416Smarkm for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 71357416Smarkm ; 71457416Smarkm if (tp->speed == -1) /* back up to last valid value */ 71557416Smarkm --tp; 71657416Smarkm cfsetospeed(&termbuf, tp->value); 71757416Smarkm#else /* DECODE_BUAD */ 71857416Smarkm cfsetospeed(&termbuf, val); 71957416Smarkm#endif /* DECODE_BUAD */ 72057416Smarkm} 72157416Smarkm 72257416Smarkmvoid 72357416Smarkmtty_rspeed(int val) 72457416Smarkm{ 72557416Smarkm#ifdef DECODE_BAUD 72657416Smarkm struct termspeeds *tp; 72757416Smarkm 72857416Smarkm for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 72957416Smarkm ; 73057416Smarkm if (tp->speed == -1) /* back up to last valid value */ 73157416Smarkm --tp; 73257416Smarkm cfsetispeed(&termbuf, tp->value); 73357416Smarkm#else /* DECODE_BAUD */ 73457416Smarkm cfsetispeed(&termbuf, val); 73557416Smarkm#endif /* DECODE_BAUD */ 73657416Smarkm} 73757416Smarkm 73857416Smarkm#ifdef PARENT_DOES_UTMP 73957416Smarkmextern struct utmp wtmp; 74057416Smarkmextern char wtmpf[]; 74157416Smarkm 74257416Smarkmextern void utmp_sig_init (void); 74357416Smarkmextern void utmp_sig_reset (void); 74457416Smarkmextern void utmp_sig_wait (void); 74557416Smarkmextern void utmp_sig_notify (int); 74657416Smarkm# endif /* PARENT_DOES_UTMP */ 74757416Smarkm 74857416Smarkm#ifdef STREAMSPTY 74957416Smarkm 75057416Smarkm/* I_FIND seems to live a life of its own */ 75157416Smarkmstatic int my_find(int fd, char *module) 75257416Smarkm{ 75357416Smarkm#if defined(I_FIND) && defined(I_LIST) 75457416Smarkm static int flag; 75557416Smarkm static struct str_list sl; 75657416Smarkm int n; 75757416Smarkm int i; 758233294Sstas 75957416Smarkm if(!flag){ 76057416Smarkm n = ioctl(fd, I_LIST, 0); 76157416Smarkm if(n < 0){ 76257416Smarkm perror("ioctl(fd, I_LIST, 0)"); 76357416Smarkm return -1; 76457416Smarkm } 76557416Smarkm sl.sl_modlist=(struct str_mlist*)malloc(n * sizeof(struct str_mlist)); 76657416Smarkm sl.sl_nmods = n; 76757416Smarkm n = ioctl(fd, I_LIST, &sl); 76857416Smarkm if(n < 0){ 76957416Smarkm perror("ioctl(fd, I_LIST, n)"); 77057416Smarkm return -1; 77157416Smarkm } 77257416Smarkm flag = 1; 77357416Smarkm } 774233294Sstas 77557416Smarkm for(i=0; i<sl.sl_nmods; i++) 77657416Smarkm if(!strcmp(sl.sl_modlist[i].l_name, module)) 77757416Smarkm return 1; 77857416Smarkm#endif 77957416Smarkm return 0; 78057416Smarkm} 78157416Smarkm 78257416Smarkmstatic void maybe_push_modules(int fd, char **modules) 78357416Smarkm{ 78457416Smarkm char **p; 78557416Smarkm int err; 78657416Smarkm 78757416Smarkm for(p=modules; *p; p++){ 78857416Smarkm err = my_find(fd, *p); 78957416Smarkm if(err == 1) 79057416Smarkm break; 79157416Smarkm if(err < 0 && errno != EINVAL) 79257416Smarkm fatalperror(net, "my_find()"); 79357416Smarkm /* module not pushed or does not exist */ 79457416Smarkm } 79557416Smarkm /* p points to null or to an already pushed module, now push all 79657416Smarkm modules before this one */ 797233294Sstas 79857416Smarkm for(p--; p >= modules; p--){ 79957416Smarkm err = ioctl(fd, I_PUSH, *p); 80057416Smarkm if(err < 0 && errno != EINVAL) 80157416Smarkm fatalperror(net, "I_PUSH"); 80257416Smarkm } 80357416Smarkm} 80457416Smarkm#endif 80557416Smarkm 80657416Smarkm/* 80757416Smarkm * getptyslave() 80857416Smarkm * 80957416Smarkm * Open the slave side of the pty, and do any initialization 81057416Smarkm * that is necessary. The return value is a file descriptor 81157416Smarkm * for the slave side. 81257416Smarkm */ 81357416Smarkmvoid getptyslave(void) 81457416Smarkm{ 81557416Smarkm int t = -1; 81657416Smarkm 81757416Smarkm struct winsize ws; 81857416Smarkm /* 81957416Smarkm * Opening the slave side may cause initilization of the 82057416Smarkm * kernel tty structure. We need remember the state of 82157416Smarkm * if linemode was turned on 82257416Smarkm * terminal window size 82357416Smarkm * terminal speed 82457416Smarkm * so that we can re-set them if we need to. 82557416Smarkm */ 82657416Smarkm 82757416Smarkm 82857416Smarkm /* 82957416Smarkm * Make sure that we don't have a controlling tty, and 83057416Smarkm * that we are the session (process group) leader. 83157416Smarkm */ 83257416Smarkm 83357416Smarkm#ifdef HAVE_SETSID 83457416Smarkm if(setsid()<0) 83557416Smarkm fatalperror(net, "setsid()"); 83657416Smarkm#else 83757416Smarkm# ifdef TIOCNOTTY 83857416Smarkm t = open(_PATH_TTY, O_RDWR); 83957416Smarkm if (t >= 0) { 84057416Smarkm ioctl(t, TIOCNOTTY, (char *)0); 84157416Smarkm close(t); 84257416Smarkm } 84357416Smarkm# endif 84457416Smarkm#endif 84557416Smarkm 84657416Smarkm# ifdef PARENT_DOES_UTMP 84757416Smarkm /* 84857416Smarkm * Wait for our parent to get the utmp stuff to get done. 84957416Smarkm */ 85057416Smarkm utmp_sig_wait(); 85157416Smarkm# endif 85257416Smarkm 85357416Smarkm t = cleanopen(line); 85457416Smarkm if (t < 0) 85557416Smarkm fatalperror(net, line); 85657416Smarkm 85757416Smarkm#ifdef STREAMSPTY 85857416Smarkm ttyfd = t; 85957416Smarkm 860233294Sstas 86157416Smarkm /* 86257416Smarkm * Not all systems have (or need) modules ttcompat and pckt so 86357416Smarkm * don't flag it as a fatal error if they don't exist. 86457416Smarkm */ 86557416Smarkm 86657416Smarkm if (really_stream) 86757416Smarkm { 86857416Smarkm /* these are the streams modules that we want pushed. note 86957416Smarkm that they are in reverse order, ptem will be pushed 87057416Smarkm first. maybe_push_modules() will try to push all modules 87157416Smarkm before the first one that isn't already pushed. i.e if 87257416Smarkm ldterm is pushed, only ttcompat will be attempted. 87357416Smarkm 87457416Smarkm all this is because we don't know which modules are 87557416Smarkm available, and we don't know which modules are already 87657416Smarkm pushed (via autopush, for instance). 87757416Smarkm 87857416Smarkm */ 879233294Sstas 88057416Smarkm char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL }; 88157416Smarkm char *ptymodules[] = { "pckt", NULL }; 88257416Smarkm 88357416Smarkm maybe_push_modules(t, ttymodules); 88457416Smarkm maybe_push_modules(ourpty, ptymodules); 88557416Smarkm } 88657416Smarkm#endif 88757416Smarkm /* 88857416Smarkm * set up the tty modes as we like them to be. 88957416Smarkm */ 89057416Smarkm init_termbuf(); 89157416Smarkm# ifdef TIOCSWINSZ 89257416Smarkm if (def_row || def_col) { 89357416Smarkm memset(&ws, 0, sizeof(ws)); 89457416Smarkm ws.ws_col = def_col; 89557416Smarkm ws.ws_row = def_row; 89657416Smarkm ioctl(t, TIOCSWINSZ, (char *)&ws); 89757416Smarkm } 89857416Smarkm# endif 89957416Smarkm 90057416Smarkm /* 90157416Smarkm * Settings for sgtty based systems 90257416Smarkm */ 90357416Smarkm 90457416Smarkm /* 90557416Smarkm * Settings for UNICOS (and HPUX) 90657416Smarkm */ 90757416Smarkm# if defined(_CRAY) || defined(__hpux) 90857416Smarkm termbuf.c_oflag = OPOST|ONLCR|TAB3; 90957416Smarkm termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON; 91057416Smarkm termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; 91157416Smarkm termbuf.c_cflag = EXTB|HUPCL|CS8; 91257416Smarkm# endif 91357416Smarkm 91457416Smarkm /* 91557416Smarkm * Settings for all other termios/termio based 91657416Smarkm * systems, other than 4.4BSD. In 4.4BSD the 91757416Smarkm * kernel does the initial terminal setup. 91857416Smarkm */ 91957416Smarkm# if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) 92057416Smarkm# ifndef OXTABS 92157416Smarkm# define OXTABS 0 92257416Smarkm# endif 92357416Smarkm termbuf.c_lflag |= ECHO; 92457416Smarkm termbuf.c_oflag |= ONLCR|OXTABS; 92557416Smarkm termbuf.c_iflag |= ICRNL; 92657416Smarkm termbuf.c_iflag &= ~IXOFF; 92757416Smarkm# endif 92857416Smarkm tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600); 92957416Smarkm tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600); 93057416Smarkm 93157416Smarkm /* 93257416Smarkm * Set the tty modes, and make this our controlling tty. 93357416Smarkm */ 93457416Smarkm set_termbuf(); 93557416Smarkm if (login_tty(t) == -1) 93657416Smarkm fatalperror(net, "login_tty"); 93757416Smarkm if (net > 2) 93857416Smarkm close(net); 93957416Smarkm if (ourpty > 2) { 94057416Smarkm close(ourpty); 94157416Smarkm ourpty = -1; 94257416Smarkm } 94357416Smarkm} 94457416Smarkm 94557416Smarkm#ifndef O_NOCTTY 94657416Smarkm#define O_NOCTTY 0 94757416Smarkm#endif 94857416Smarkm/* 94957416Smarkm * Open the specified slave side of the pty, 95057416Smarkm * making sure that we have a clean tty. 95157416Smarkm */ 95257416Smarkm 95357416Smarkmint cleanopen(char *line) 95457416Smarkm{ 95557416Smarkm int t; 95657416Smarkm 957178825Sdfr if (ptyslavefd != -1) 958178825Sdfr return ptyslavefd; 959178825Sdfr 96057416Smarkm#ifdef STREAMSPTY 96157416Smarkm if (!really_stream) 96257416Smarkm#endif 96357416Smarkm { 96457416Smarkm /* 96557416Smarkm * Make sure that other people can't open the 96657416Smarkm * slave side of the connection. 96757416Smarkm */ 96857416Smarkm chown(line, 0, 0); 96957416Smarkm chmod(line, 0600); 97057416Smarkm } 97157416Smarkm 97257416Smarkm#ifdef HAVE_REVOKE 97357416Smarkm revoke(line); 97457416Smarkm#endif 97557416Smarkm 97657416Smarkm t = open(line, O_RDWR|O_NOCTTY); 97757416Smarkm 97857416Smarkm if (t < 0) 97957416Smarkm return(-1); 98057416Smarkm 98157416Smarkm /* 98257416Smarkm * Hangup anybody else using this ttyp, then reopen it for 98357416Smarkm * ourselves. 98457416Smarkm */ 98557416Smarkm# if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY) 98657416Smarkm signal(SIGHUP, SIG_IGN); 98757416Smarkm#ifdef HAVE_VHANGUP 98857416Smarkm vhangup(); 98957416Smarkm#else 99057416Smarkm#endif 99157416Smarkm signal(SIGHUP, SIG_DFL); 99257416Smarkm t = open(line, O_RDWR|O_NOCTTY); 99357416Smarkm if (t < 0) 99457416Smarkm return(-1); 99557416Smarkm# endif 99657416Smarkm# if defined(_CRAY) && defined(TCVHUP) 99757416Smarkm { 99857416Smarkm int i; 99957416Smarkm signal(SIGHUP, SIG_IGN); 100057416Smarkm ioctl(t, TCVHUP, (char *)0); 100157416Smarkm signal(SIGHUP, SIG_DFL); 100257416Smarkm 100357416Smarkm i = open(line, O_RDWR); 100457416Smarkm 100557416Smarkm if (i < 0) 100657416Smarkm return(-1); 100757416Smarkm close(t); 100857416Smarkm t = i; 100957416Smarkm } 101057416Smarkm# endif /* defined(CRAY) && defined(TCVHUP) */ 101157416Smarkm return(t); 101257416Smarkm} 101357416Smarkm 101457416Smarkm#if !defined(BSD4_4) 101557416Smarkm 101657416Smarkmint login_tty(int t) 101757416Smarkm{ 1018233294Sstas /* Dont need to set this as the controlling PTY on steams sockets, 1019233294Sstas * don't abort on failure. */ 102057416Smarkm# if defined(TIOCSCTTY) && !defined(__hpux) 1021233294Sstas if (ioctl(t, TIOCSCTTY, (char *)0) < 0 && !really_stream) 102257416Smarkm fatalperror(net, "ioctl(sctty)"); 102357416Smarkm# ifdef _CRAY 102457416Smarkm /* 102557416Smarkm * Close the hard fd to /dev/ttypXXX, and re-open through 102657416Smarkm * the indirect /dev/tty interface. 102757416Smarkm */ 102857416Smarkm close(t); 102957416Smarkm if ((t = open("/dev/tty", O_RDWR)) < 0) 103057416Smarkm fatalperror(net, "open(/dev/tty)"); 103157416Smarkm# endif 103257416Smarkm# else 103357416Smarkm /* 103457416Smarkm * We get our controlling tty assigned as a side-effect 103557416Smarkm * of opening up a tty device. But on BSD based systems, 103657416Smarkm * this only happens if our process group is zero. The 103757416Smarkm * setsid() call above may have set our pgrp, so clear 103857416Smarkm * it out before opening the tty... 103957416Smarkm */ 104057416Smarkm#ifdef HAVE_SETPGID 104157416Smarkm setpgid(0, 0); 104257416Smarkm#else 104357416Smarkm setpgrp(0, 0); /* if setpgid isn't available, setpgrp 104457416Smarkm probably takes arguments */ 104557416Smarkm#endif 104657416Smarkm close(open(line, O_RDWR)); 104757416Smarkm# endif 104857416Smarkm if (t != 0) 104957416Smarkm dup2(t, 0); 105057416Smarkm if (t != 1) 105157416Smarkm dup2(t, 1); 105257416Smarkm if (t != 2) 105357416Smarkm dup2(t, 2); 105457416Smarkm if (t > 2) 105557416Smarkm close(t); 105657416Smarkm return(0); 105757416Smarkm} 105857416Smarkm#endif /* BSD <= 43 */ 105957416Smarkm 106057416Smarkm/* 106157416Smarkm * This comes from ../../bsd/tty.c and should not really be here. 106257416Smarkm */ 106357416Smarkm 106457416Smarkm/* 106557416Smarkm * Clean the tty name. Return a pointer to the cleaned version. 106657416Smarkm */ 106757416Smarkm 1068178825Sdfrstatic char * clean_ttyname (char *) __attribute__((unused)); 1069178825Sdfr 107057416Smarkmstatic char * 107157416Smarkmclean_ttyname (char *tty) 107257416Smarkm{ 107357416Smarkm char *res = tty; 107457416Smarkm 107557416Smarkm if (strncmp (res, _PATH_DEV, strlen(_PATH_DEV)) == 0) 107657416Smarkm res += strlen(_PATH_DEV); 107757416Smarkm if (strncmp (res, "pty/", 4) == 0) 107857416Smarkm res += 4; 107957416Smarkm if (strncmp (res, "ptym/", 5) == 0) 108057416Smarkm res += 5; 108157416Smarkm return res; 108257416Smarkm} 108357416Smarkm 108457416Smarkm/* 108557416Smarkm * Generate a name usable as an `ut_id', typically without `tty'. 108657416Smarkm */ 108757416Smarkm 108857416Smarkm#ifdef HAVE_STRUCT_UTMP_UT_ID 108957416Smarkmstatic char * 109057416Smarkmmake_id (char *tty) 109157416Smarkm{ 109257416Smarkm char *res = tty; 1093233294Sstas 109457416Smarkm if (strncmp (res, "pts/", 4) == 0) 109557416Smarkm res += 4; 109657416Smarkm if (strncmp (res, "tty", 3) == 0) 109757416Smarkm res += 3; 109857416Smarkm return res; 109957416Smarkm} 110057416Smarkm#endif 110157416Smarkm 110257416Smarkm/* 110357416Smarkm * startslave(host) 110457416Smarkm * 110557416Smarkm * Given a hostname, do whatever 110657416Smarkm * is necessary to startup the login process on the slave side of the pty. 110757416Smarkm */ 110857416Smarkm 110957416Smarkm/* ARGSUSED */ 111057416Smarkmvoid 111178527Sassarstartslave(const char *host, const char *utmp_host, 111278527Sassar int autologin, char *autoname) 111357416Smarkm{ 111457416Smarkm int i; 111557416Smarkm 111657416Smarkm#ifdef AUTHENTICATION 111757416Smarkm if (!autoname || !autoname[0]) 111857416Smarkm autologin = 0; 111957416Smarkm 112057416Smarkm if (autologin < auth_level) { 112157416Smarkm fatal(net, "Authorization failed"); 112257416Smarkm exit(1); 112357416Smarkm } 112457416Smarkm#endif 112557416Smarkm 112657416Smarkm { 112757416Smarkm char *tbuf = 112857416Smarkm "\r\n*** Connection not encrypted! " 112957416Smarkm "Communication may be eavesdropped. ***\r\n"; 113057416Smarkm#ifdef ENCRYPTION 113157416Smarkm if (!no_warn && (encrypt_output == 0 || decrypt_input == 0)) 113257416Smarkm#endif 1133178825Sdfr writenet(tbuf, strlen(tbuf)); 113457416Smarkm } 113557416Smarkm# ifdef PARENT_DOES_UTMP 113657416Smarkm utmp_sig_init(); 113757416Smarkm# endif /* PARENT_DOES_UTMP */ 113857416Smarkm 113957416Smarkm if ((i = fork()) < 0) 114057416Smarkm fatalperror(net, "fork"); 114157416Smarkm if (i) { 114257416Smarkm# ifdef PARENT_DOES_UTMP 114357416Smarkm /* 114457416Smarkm * Cray parent will create utmp entry for child and send 114557416Smarkm * signal to child to tell when done. Child waits for signal 114657416Smarkm * before doing anything important. 114757416Smarkm */ 114857416Smarkm int pid = i; 114957416Smarkm void sigjob (int); 115057416Smarkm 115157416Smarkm setpgrp(); 115257416Smarkm utmp_sig_reset(); /* reset handler to default */ 115357416Smarkm /* 115457416Smarkm * Create utmp entry for child 115557416Smarkm */ 115672445Sassar wtmp.ut_time = time(NULL); 115757416Smarkm wtmp.ut_type = LOGIN_PROCESS; 115857416Smarkm wtmp.ut_pid = pid; 115957416Smarkm strncpy(wtmp.ut_user, "LOGIN", sizeof(wtmp.ut_user)); 116078527Sassar strncpy(wtmp.ut_host, utmp_host, sizeof(wtmp.ut_host)); 116157416Smarkm strncpy(wtmp.ut_line, clean_ttyname(line), sizeof(wtmp.ut_line)); 116257416Smarkm#ifdef HAVE_STRUCT_UTMP_UT_ID 116357416Smarkm strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id)); 116457416Smarkm#endif 116557416Smarkm 116657416Smarkm pututline(&wtmp); 116757416Smarkm endutent(); 116857416Smarkm if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) { 116957416Smarkm write(i, &wtmp, sizeof(struct utmp)); 117057416Smarkm close(i); 117157416Smarkm } 117257416Smarkm#ifdef _CRAY 117357416Smarkm signal(WJSIGNAL, sigjob); 117457416Smarkm#endif 117557416Smarkm utmp_sig_notify(pid); 117657416Smarkm# endif /* PARENT_DOES_UTMP */ 117757416Smarkm } else { 117857416Smarkm getptyslave(); 117972445Sassar#if defined(DCE) 118072445Sassar /* if we authenticated via K5, try and join the PAG */ 118172445Sassar kerberos5_dfspag(); 118272445Sassar#endif 118357416Smarkm start_login(host, autologin, autoname); 118457416Smarkm /*NOTREACHED*/ 118557416Smarkm } 118657416Smarkm} 118757416Smarkm 118857416Smarkmchar *envinit[3]; 1189233294Sstas#if !HAVE_DECL_ENVIRON 119057416Smarkmextern char **environ; 1191233294Sstas#endif 119257416Smarkm 119357416Smarkmvoid 119457416Smarkminit_env(void) 119557416Smarkm{ 119657416Smarkm char **envp; 119757416Smarkm 119857416Smarkm envp = envinit; 119957416Smarkm if ((*envp = getenv("TZ"))) 120057416Smarkm *envp++ -= 3; 120157416Smarkm#if defined(_CRAY) || defined(__hpux) 120257416Smarkm else 120357416Smarkm *envp++ = "TZ=GMT0"; 120457416Smarkm#endif 120557416Smarkm *envp = 0; 120657416Smarkm environ = envinit; 120757416Smarkm} 120857416Smarkm 120957416Smarkm/* 121057416Smarkm * scrub_env() 121157416Smarkm * 121272445Sassar * We only accept the environment variables listed below. 121357416Smarkm */ 121457416Smarkm 121572445Sassarstatic void 121672445Sassarscrub_env(void) 121757416Smarkm{ 121872445Sassar static const char *reject[] = { 121972445Sassar "TERMCAP=/", 122072445Sassar NULL 122172445Sassar }; 122257416Smarkm 122372445Sassar static const char *accept[] = { 122472445Sassar "XAUTH=", "XAUTHORITY=", "DISPLAY=", 122572445Sassar "TERM=", 122672445Sassar "EDITOR=", 122772445Sassar "PAGER=", 122872445Sassar "PRINTER=", 122972445Sassar "LOGNAME=", 123072445Sassar "POSIXLY_CORRECT=", 123172445Sassar "TERMCAP=", 123272445Sassar NULL 123372445Sassar }; 123472445Sassar 123557416Smarkm char **cpp, **cpp2; 123672445Sassar const char **p; 1237233294Sstas 123857416Smarkm for (cpp2 = cpp = environ; *cpp; cpp++) { 123972445Sassar int reject_it = 0; 124072445Sassar 124172445Sassar for(p = reject; *p; p++) 124272445Sassar if(strncmp(*cpp, *p, strlen(*p)) == 0) { 124372445Sassar reject_it = 1; 124472445Sassar break; 124572445Sassar } 124672445Sassar if (reject_it) 124772445Sassar continue; 124872445Sassar 124972445Sassar for(p = accept; *p; p++) 125057416Smarkm if(strncmp(*cpp, *p, strlen(*p)) == 0) 125157416Smarkm break; 125272445Sassar if(*p != NULL) 125357416Smarkm *cpp2++ = *cpp; 125457416Smarkm } 125572445Sassar *cpp2 = NULL; 125657416Smarkm} 125757416Smarkm 125857416Smarkm 125957416Smarkmstruct arg_val { 126057416Smarkm int size; 126157416Smarkm int argc; 1262178825Sdfr char **argv; 126357416Smarkm}; 126457416Smarkm 126578527Sassarstatic void addarg(struct arg_val*, const char*); 126657416Smarkm 126757416Smarkm/* 126857416Smarkm * start_login(host) 126957416Smarkm * 127057416Smarkm * Assuming that we are now running as a child processes, this 127157416Smarkm * function will turn us into the login process. 127257416Smarkm */ 127357416Smarkm 127457416Smarkmvoid 127578527Sassarstart_login(const char *host, int autologin, char *name) 127657416Smarkm{ 127757416Smarkm struct arg_val argv; 127857416Smarkm char *user; 127978527Sassar int save_errno; 128057416Smarkm 1281178825Sdfr#ifdef ENCRYPTION 1282178825Sdfr encrypt_output = NULL; 1283178825Sdfr decrypt_input = NULL; 1284178825Sdfr#endif 1285233294Sstas 128657416Smarkm#ifdef HAVE_UTMPX_H 1287178825Sdfr { 1288178825Sdfr int pid = getpid(); 1289178825Sdfr struct utmpx utmpx; 1290178825Sdfr struct timeval tv; 1291178825Sdfr char *clean_tty; 1292233294Sstas 1293178825Sdfr /* 1294178825Sdfr * Create utmp entry for child 1295178825Sdfr */ 1296233294Sstas 1297178825Sdfr clean_tty = clean_ttyname(line); 1298178825Sdfr memset(&utmpx, 0, sizeof(utmpx)); 1299178825Sdfr strncpy(utmpx.ut_user, ".telnet", sizeof(utmpx.ut_user)); 1300178825Sdfr strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line)); 130157416Smarkm#ifdef HAVE_STRUCT_UTMP_UT_ID 1302178825Sdfr strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id)); 130357416Smarkm#endif 1304178825Sdfr utmpx.ut_pid = pid; 1305233294Sstas 1306178825Sdfr utmpx.ut_type = LOGIN_PROCESS; 1307233294Sstas 1308178825Sdfr gettimeofday (&tv, NULL); 1309178825Sdfr utmpx.ut_tv.tv_sec = tv.tv_sec; 1310178825Sdfr utmpx.ut_tv.tv_usec = tv.tv_usec; 131157416Smarkm 1312178825Sdfr if (pututxline(&utmpx) == NULL) 1313178825Sdfr fatal(net, "pututxline failed"); 1314178825Sdfr } 131557416Smarkm#endif 131657416Smarkm 131757416Smarkm scrub_env(); 1318233294Sstas 131957416Smarkm /* 132057416Smarkm * -h : pass on name of host. 132157416Smarkm * WARNING: -h is accepted by login if and only if 132257416Smarkm * getuid() == 0. 132357416Smarkm * -p : don't clobber the environment (so terminal type stays set). 132457416Smarkm * 132557416Smarkm * -f : force this login, he has already been authenticated 132657416Smarkm */ 132757416Smarkm 1328233294Sstas /* init argv structure */ 132957416Smarkm argv.size=0; 133057416Smarkm argv.argc=0; 133178527Sassar argv.argv=malloc(0); /*so we can call realloc later */ 133257416Smarkm addarg(&argv, "login"); 133357416Smarkm addarg(&argv, "-h"); 133457416Smarkm addarg(&argv, host); 133557416Smarkm addarg(&argv, "-p"); 1336233294Sstas if(name && name[0]) 133757416Smarkm user = name; 133857416Smarkm else 133957416Smarkm user = getenv("USER"); 134057416Smarkm#ifdef AUTHENTICATION 134157416Smarkm if (auth_level < 0 || autologin != AUTH_VALID) { 134257416Smarkm if(!no_warn) { 134357416Smarkm printf("User not authenticated. "); 134457416Smarkm if (require_otp) 134557416Smarkm printf("Using one-time password\r\n"); 134657416Smarkm else 134757416Smarkm printf("Using plaintext username and password\r\n"); 134857416Smarkm } 134957416Smarkm if (require_otp) { 135057416Smarkm addarg(&argv, "-a"); 135157416Smarkm addarg(&argv, "otp"); 135257416Smarkm } 1353233294Sstas if(log_unauth) 1354233294Sstas syslog(LOG_INFO, "unauthenticated access from %s (%s)", 135557416Smarkm host, user ? user : "unknown user"); 135657416Smarkm } 135757416Smarkm if (auth_level >= 0 && autologin == AUTH_VALID) 135857416Smarkm addarg(&argv, "-f"); 135957416Smarkm#endif 136057416Smarkm if(user){ 136157416Smarkm addarg(&argv, "--"); 136257416Smarkm addarg(&argv, strdup(user)); 136357416Smarkm } 136457416Smarkm if (getenv("USER")) { 136557416Smarkm /* 136657416Smarkm * Assume that login will set the USER variable 136757416Smarkm * correctly. For SysV systems, this means that 136857416Smarkm * USER will no longer be set, just LOGNAME by 136957416Smarkm * login. (The problem is that if the auto-login 137057416Smarkm * fails, and the user then specifies a different 137157416Smarkm * account name, he can get logged in with both 137257416Smarkm * LOGNAME and USER in his environment, but the 137357416Smarkm * USER value will be wrong. 137457416Smarkm */ 137557416Smarkm unsetenv("USER"); 137657416Smarkm } 137757416Smarkm closelog(); 137857416Smarkm /* 137957416Smarkm * This sleep(1) is in here so that telnetd can 138057416Smarkm * finish up with the tty. There's a race condition 138157416Smarkm * the login banner message gets lost... 138257416Smarkm */ 138357416Smarkm sleep(1); 138457416Smarkm 138557416Smarkm execv(new_login, argv.argv); 138678527Sassar save_errno = errno; 1387178825Sdfr syslog(LOG_ERR, "%s: %m", new_login); 138878527Sassar fatalperror_errno(net, new_login, save_errno); 138957416Smarkm /*NOTREACHED*/ 139057416Smarkm} 139157416Smarkm 139257416Smarkmstatic void 139378527Sassaraddarg(struct arg_val *argv, const char *val) 139457416Smarkm{ 139557416Smarkm if(argv->size <= argv->argc+1) { 139657416Smarkm argv->argv = realloc(argv->argv, sizeof(char*) * (argv->size + 10)); 139757416Smarkm if (argv->argv == NULL) 139857416Smarkm fatal (net, "realloc: out of memory"); 139957416Smarkm argv->size+=10; 140057416Smarkm } 1401178825Sdfr if((argv->argv[argv->argc++] = strdup(val)) == NULL) 1402178825Sdfr fatal (net, "strdup: out of memory"); 140357416Smarkm argv->argv[argv->argc] = NULL; 140457416Smarkm} 140557416Smarkm 140657416Smarkm 140757416Smarkm/* 140857416Smarkm * rmut() 140957416Smarkm * 141057416Smarkm * This is the function called by cleanup() to 141157416Smarkm * remove the utmp entry for this person. 141257416Smarkm */ 141357416Smarkm 141457416Smarkm#ifdef HAVE_UTMPX_H 141557416Smarkmstatic void 141657416Smarkmrmut(void) 141757416Smarkm{ 141857416Smarkm struct utmpx utmpx, *non_save_utxp; 141957416Smarkm char *clean_tty = clean_ttyname(line); 142057416Smarkm 142157416Smarkm /* 142257416Smarkm * This updates the utmpx and utmp entries and make a wtmp/x entry 142357416Smarkm */ 142457416Smarkm 142557416Smarkm setutxent(); 142657416Smarkm memset(&utmpx, 0, sizeof(utmpx)); 142757416Smarkm strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line)); 142857416Smarkm utmpx.ut_type = LOGIN_PROCESS; 142957416Smarkm non_save_utxp = getutxline(&utmpx); 143057416Smarkm if (non_save_utxp) { 143157416Smarkm struct utmpx *utxp; 1432178825Sdfr struct timeval tv; 143357416Smarkm char user0; 143457416Smarkm 143557416Smarkm utxp = malloc(sizeof(struct utmpx)); 143657416Smarkm *utxp = *non_save_utxp; 143757416Smarkm user0 = utxp->ut_user[0]; 143857416Smarkm utxp->ut_user[0] = '\0'; 143957416Smarkm utxp->ut_type = DEAD_PROCESS; 144057416Smarkm#ifdef HAVE_STRUCT_UTMPX_UT_EXIT 144157416Smarkm#ifdef _STRUCT___EXIT_STATUS 144257416Smarkm utxp->ut_exit.__e_termination = 0; 144357416Smarkm utxp->ut_exit.__e_exit = 0; 144457416Smarkm#elif defined(__osf__) /* XXX */ 144557416Smarkm utxp->ut_exit.ut_termination = 0; 144657416Smarkm utxp->ut_exit.ut_exit = 0; 1447233294Sstas#else 144857416Smarkm utxp->ut_exit.e_termination = 0; 144957416Smarkm utxp->ut_exit.e_exit = 0; 145057416Smarkm#endif 145157416Smarkm#endif 1452178825Sdfr gettimeofday (&tv, NULL); 1453178825Sdfr utxp->ut_tv.tv_sec = tv.tv_sec; 1454178825Sdfr utxp->ut_tv.tv_usec = tv.tv_usec; 1455178825Sdfr 145657416Smarkm pututxline(utxp); 145757416Smarkm#ifdef WTMPX_FILE 145857416Smarkm utxp->ut_user[0] = user0; 145957416Smarkm updwtmpx(WTMPX_FILE, utxp); 146057416Smarkm#elif defined(WTMP_FILE) 146157416Smarkm /* This is a strange system with a utmpx and a wtmp! */ 146257416Smarkm { 146357416Smarkm int f = open(wtmpf, O_WRONLY|O_APPEND); 146457416Smarkm struct utmp wtmp; 146557416Smarkm if (f >= 0) { 146657416Smarkm strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line)); 146757416Smarkm strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name)); 146857416Smarkm#ifdef HAVE_STRUCT_UTMP_UT_HOST 146957416Smarkm strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host)); 147057416Smarkm#endif 147172445Sassar wtmp.ut_time = time(NULL); 147257416Smarkm write(f, &wtmp, sizeof(wtmp)); 147357416Smarkm close(f); 147457416Smarkm } 147557416Smarkm } 147657416Smarkm#endif 147757416Smarkm free (utxp); 147857416Smarkm } 147957416Smarkm endutxent(); 148057416Smarkm} /* end of rmut */ 148157416Smarkm#endif 148257416Smarkm 148357416Smarkm#if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43 148457416Smarkmstatic void 148557416Smarkmrmut(void) 148657416Smarkm{ 148757416Smarkm int f; 148857416Smarkm int found = 0; 148957416Smarkm struct utmp *u, *utmp; 149057416Smarkm int nutmp; 149157416Smarkm struct stat statbf; 149257416Smarkm char *clean_tty = clean_ttyname(line); 149357416Smarkm 149457416Smarkm f = open(utmpf, O_RDWR); 149557416Smarkm if (f >= 0) { 149657416Smarkm fstat(f, &statbf); 149757416Smarkm utmp = (struct utmp *)malloc((unsigned)statbf.st_size); 149857416Smarkm if (!utmp) 149957416Smarkm syslog(LOG_ERR, "utmp malloc failed"); 150057416Smarkm if (statbf.st_size && utmp) { 150157416Smarkm nutmp = read(f, utmp, (int)statbf.st_size); 150257416Smarkm nutmp /= sizeof(struct utmp); 150357416Smarkm 150457416Smarkm for (u = utmp ; u < &utmp[nutmp] ; u++) { 150557416Smarkm if (strncmp(u->ut_line, 150657416Smarkm clean_tty, 150757416Smarkm sizeof(u->ut_line)) || 150857416Smarkm u->ut_name[0]==0) 150957416Smarkm continue; 151057416Smarkm lseek(f, ((long)u)-((long)utmp), L_SET); 151157416Smarkm strncpy(u->ut_name, "", sizeof(u->ut_name)); 151257416Smarkm#ifdef HAVE_STRUCT_UTMP_UT_HOST 151357416Smarkm strncpy(u->ut_host, "", sizeof(u->ut_host)); 151457416Smarkm#endif 151572445Sassar u->ut_time = time(NULL); 151657416Smarkm write(f, u, sizeof(wtmp)); 151757416Smarkm found++; 151857416Smarkm } 151957416Smarkm } 152057416Smarkm close(f); 152157416Smarkm } 152257416Smarkm if (found) { 152357416Smarkm f = open(wtmpf, O_WRONLY|O_APPEND); 152457416Smarkm if (f >= 0) { 152557416Smarkm strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line)); 152657416Smarkm strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name)); 152757416Smarkm#ifdef HAVE_STRUCT_UTMP_UT_HOST 152857416Smarkm strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host)); 152957416Smarkm#endif 153072445Sassar wtmp.ut_time = time(NULL); 153157416Smarkm write(f, &wtmp, sizeof(wtmp)); 153257416Smarkm close(f); 153357416Smarkm } 153457416Smarkm } 153557416Smarkm chmod(line, 0666); 153657416Smarkm chown(line, 0, 0); 153757416Smarkm line[strlen("/dev/")] = 'p'; 153857416Smarkm chmod(line, 0666); 153957416Smarkm chown(line, 0, 0); 154057416Smarkm} /* end of rmut */ 154157416Smarkm#endif /* CRAY */ 154257416Smarkm 154357416Smarkm#if defined(__hpux) && !defined(HAVE_UTMPX_H) 154457416Smarkmstatic void 154557416Smarkmrmut (char *line) 154657416Smarkm{ 154757416Smarkm struct utmp utmp; 154857416Smarkm struct utmp *utptr; 154957416Smarkm int fd; /* for /etc/wtmp */ 155057416Smarkm 155157416Smarkm utmp.ut_type = USER_PROCESS; 155257416Smarkm strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line)); 155357416Smarkm setutent(); 155457416Smarkm utptr = getutline(&utmp); 155557416Smarkm /* write it out only if it exists */ 155657416Smarkm if (utptr) { 155757416Smarkm utptr->ut_type = DEAD_PROCESS; 155857416Smarkm utptr->ut_time = time(NULL); 155957416Smarkm pututline(utptr); 156057416Smarkm /* set wtmp entry if wtmp file exists */ 156157416Smarkm if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) { 156257416Smarkm write(fd, utptr, sizeof(utmp)); 156357416Smarkm close(fd); 156457416Smarkm } 156557416Smarkm } 156657416Smarkm endutent(); 156757416Smarkm 156857416Smarkm chmod(line, 0666); 156957416Smarkm chown(line, 0, 0); 157057416Smarkm line[14] = line[13]; 157157416Smarkm line[13] = line[12]; 157257416Smarkm line[8] = 'm'; 157357416Smarkm line[9] = '/'; 157457416Smarkm line[10] = 'p'; 157557416Smarkm line[11] = 't'; 157657416Smarkm line[12] = 'y'; 157757416Smarkm chmod(line, 0666); 157857416Smarkm chown(line, 0, 0); 157957416Smarkm} 158057416Smarkm#endif 158157416Smarkm 158257416Smarkm/* 158357416Smarkm * cleanup() 158457416Smarkm * 158557416Smarkm * This is the routine to call when we are all through, to 158657416Smarkm * clean up anything that needs to be cleaned up. 158757416Smarkm */ 158857416Smarkm 158957416Smarkm#ifdef PARENT_DOES_UTMP 159057416Smarkm 159157416Smarkmvoid 159257416Smarkmcleanup(int sig) 159357416Smarkm{ 159457416Smarkm#ifdef _CRAY 159557416Smarkm static int incleanup = 0; 159657416Smarkm int t; 159757416Smarkm int child_status; /* status of child process as returned by waitpid */ 159857416Smarkm int flags = WNOHANG|WUNTRACED; 1599233294Sstas 160057416Smarkm /* 160157416Smarkm * 1: Pick up the zombie, if we are being called 160257416Smarkm * as the signal handler. 160357416Smarkm * 2: If we are a nested cleanup(), return. 160457416Smarkm * 3: Try to clean up TMPDIR. 160557416Smarkm * 4: Fill in utmp with shutdown of process. 160657416Smarkm * 5: Close down the network and pty connections. 160757416Smarkm * 6: Finish up the TMPDIR cleanup, if needed. 160857416Smarkm */ 160957416Smarkm if (sig == SIGCHLD) { 161057416Smarkm while (waitpid(-1, &child_status, flags) > 0) 161157416Smarkm ; /* VOID */ 161257416Smarkm /* Check if the child process was stopped 161357416Smarkm * rather than exited. We want cleanup only if 161457416Smarkm * the child has died. 161557416Smarkm */ 161657416Smarkm if (WIFSTOPPED(child_status)) { 161757416Smarkm return; 161857416Smarkm } 161957416Smarkm } 162057416Smarkm t = sigblock(sigmask(SIGCHLD)); 162157416Smarkm if (incleanup) { 162257416Smarkm sigsetmask(t); 162357416Smarkm return; 162457416Smarkm } 162557416Smarkm incleanup = 1; 162657416Smarkm sigsetmask(t); 1627233294Sstas 162857416Smarkm t = cleantmp(&wtmp); 162957416Smarkm setutent(); /* just to make sure */ 163057416Smarkm#endif /* CRAY */ 163157416Smarkm rmut(line); 163257416Smarkm close(ourpty); 163357416Smarkm shutdown(net, 2); 163457416Smarkm#ifdef _CRAY 163557416Smarkm if (t == 0) 163657416Smarkm cleantmp(&wtmp); 163757416Smarkm#endif /* CRAY */ 163857416Smarkm exit(1); 163957416Smarkm} 164057416Smarkm 164157416Smarkm#else /* PARENT_DOES_UTMP */ 164257416Smarkm 164357416Smarkmvoid 164457416Smarkmcleanup(int sig) 164557416Smarkm{ 164657416Smarkm#if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP) 164757416Smarkm rmut(); 164857416Smarkm#ifdef HAVE_VHANGUP 164957416Smarkm#ifndef __sgi 165057416Smarkm vhangup(); /* XXX */ 165157416Smarkm#endif 165257416Smarkm#endif 165357416Smarkm#else 165457416Smarkm char *p; 1655233294Sstas 165657416Smarkm p = line + sizeof("/dev/") - 1; 165757416Smarkm if (logout(p)) 165857416Smarkm logwtmp(p, "", ""); 165957416Smarkm chmod(line, 0666); 166057416Smarkm chown(line, 0, 0); 166157416Smarkm *p = 'p'; 166257416Smarkm chmod(line, 0666); 166357416Smarkm chown(line, 0, 0); 166457416Smarkm#endif 166557416Smarkm shutdown(net, 2); 166657416Smarkm exit(1); 166757416Smarkm} 166857416Smarkm 166957416Smarkm#endif /* PARENT_DOES_UTMP */ 167057416Smarkm 167157416Smarkm#ifdef PARENT_DOES_UTMP 167257416Smarkm/* 167357416Smarkm * _utmp_sig_rcv 167457416Smarkm * utmp_sig_init 167557416Smarkm * utmp_sig_wait 167657416Smarkm * These three functions are used to coordinate the handling of 167757416Smarkm * the utmp file between the server and the soon-to-be-login shell. 167857416Smarkm * The server actually creates the utmp structure, the child calls 167957416Smarkm * utmp_sig_wait(), until the server calls utmp_sig_notify() and 168057416Smarkm * signals the future-login shell to proceed. 168157416Smarkm */ 168257416Smarkmstatic int caught=0; /* NZ when signal intercepted */ 168357416Smarkmstatic void (*func)(); /* address of previous handler */ 168457416Smarkm 168557416Smarkmvoid 168657416Smarkm_utmp_sig_rcv(sig) 168757416Smarkm int sig; 168857416Smarkm{ 168957416Smarkm caught = 1; 169057416Smarkm signal(SIGUSR1, func); 169157416Smarkm} 169257416Smarkm 169357416Smarkmvoid 169457416Smarkmutmp_sig_init() 169557416Smarkm{ 169657416Smarkm /* 169757416Smarkm * register signal handler for UTMP creation 169857416Smarkm */ 169957416Smarkm if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1) 170057416Smarkm fatalperror(net, "telnetd/signal"); 170157416Smarkm} 170257416Smarkm 170357416Smarkmvoid 170457416Smarkmutmp_sig_reset() 170557416Smarkm{ 170657416Smarkm signal(SIGUSR1, func); /* reset handler to default */ 170757416Smarkm} 170857416Smarkm 170957416Smarkm# ifdef __hpux 171057416Smarkm# define sigoff() /* do nothing */ 171157416Smarkm# define sigon() /* do nothing */ 171257416Smarkm# endif 171357416Smarkm 171457416Smarkmvoid 171557416Smarkmutmp_sig_wait() 171657416Smarkm{ 171757416Smarkm /* 171857416Smarkm * Wait for parent to write our utmp entry. 171957416Smarkm */ 172057416Smarkm sigoff(); 172157416Smarkm while (caught == 0) { 172257416Smarkm pause(); /* wait until we get a signal (sigon) */ 172357416Smarkm sigoff(); /* turn off signals while we check caught */ 172457416Smarkm } 172557416Smarkm sigon(); /* turn on signals again */ 172657416Smarkm} 172757416Smarkm 172857416Smarkmvoid 172957416Smarkmutmp_sig_notify(pid) 173057416Smarkm{ 173157416Smarkm kill(pid, SIGUSR1); 173257416Smarkm} 173357416Smarkm 173457416Smarkm#ifdef _CRAY 173557416Smarkmstatic int gotsigjob = 0; 173657416Smarkm 173757416Smarkm /*ARGSUSED*/ 173857416Smarkmvoid 173957416Smarkmsigjob(sig) 174057416Smarkm int sig; 174157416Smarkm{ 174257416Smarkm int jid; 174357416Smarkm struct jobtemp *jp; 174457416Smarkm 174557416Smarkm while ((jid = waitjob(NULL)) != -1) { 174657416Smarkm if (jid == 0) { 174757416Smarkm return; 174857416Smarkm } 174957416Smarkm gotsigjob++; 175057416Smarkm jobend(jid, NULL, NULL); 175157416Smarkm } 175257416Smarkm} 175357416Smarkm 175457416Smarkm/* 175557416Smarkm * jid_getutid: 175657416Smarkm * called by jobend() before calling cleantmp() 175757416Smarkm * to find the correct $TMPDIR to cleanup. 175857416Smarkm */ 175957416Smarkm 176057416Smarkmstruct utmp * 176157416Smarkmjid_getutid(jid) 176257416Smarkm int jid; 176357416Smarkm{ 176457416Smarkm struct utmp *cur = NULL; 176557416Smarkm 176657416Smarkm setutent(); /* just to make sure */ 176757416Smarkm while (cur = getutent()) { 176857416Smarkm if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) { 176957416Smarkm return(cur); 177057416Smarkm } 177157416Smarkm } 177257416Smarkm 177357416Smarkm return(0); 177457416Smarkm} 177557416Smarkm 177657416Smarkm/* 177757416Smarkm * Clean up the TMPDIR that login created. 177857416Smarkm * The first time this is called we pick up the info 177957416Smarkm * from the utmp. If the job has already gone away, 178057416Smarkm * then we'll clean up and be done. If not, then 178157416Smarkm * when this is called the second time it will wait 178257416Smarkm * for the signal that the job is done. 178357416Smarkm */ 178457416Smarkmint 178557416Smarkmcleantmp(wtp) 178657416Smarkm struct utmp *wtp; 178757416Smarkm{ 178857416Smarkm struct utmp *utp; 178957416Smarkm static int first = 1; 179057416Smarkm int mask, omask, ret; 179157416Smarkm extern struct utmp *getutid (const struct utmp *_Id); 179257416Smarkm 179357416Smarkm 179457416Smarkm mask = sigmask(WJSIGNAL); 179557416Smarkm 179657416Smarkm if (first == 0) { 179757416Smarkm omask = sigblock(mask); 179857416Smarkm while (gotsigjob == 0) 179957416Smarkm sigpause(omask); 180057416Smarkm return(1); 180157416Smarkm } 180257416Smarkm first = 0; 180357416Smarkm setutent(); /* just to make sure */ 180457416Smarkm 180557416Smarkm utp = getutid(wtp); 180657416Smarkm if (utp == 0) { 180757416Smarkm syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); 180857416Smarkm return(-1); 180957416Smarkm } 181057416Smarkm /* 181157416Smarkm * Nothing to clean up if the user shell was never started. 181257416Smarkm */ 181357416Smarkm if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0) 181457416Smarkm return(1); 181557416Smarkm 181657416Smarkm /* 181757416Smarkm * Block the WJSIGNAL while we are in jobend(). 181857416Smarkm */ 181957416Smarkm omask = sigblock(mask); 182057416Smarkm ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user); 182157416Smarkm sigsetmask(omask); 182257416Smarkm return(ret); 182357416Smarkm} 182457416Smarkm 182557416Smarkmint 182657416Smarkmjobend(jid, path, user) 182757416Smarkm int jid; 182857416Smarkm char *path; 182957416Smarkm char *user; 183057416Smarkm{ 183157416Smarkm static int saved_jid = 0; 183257416Smarkm static int pty_saved_jid = 0; 183357416Smarkm static char saved_path[sizeof(wtmp.ut_tpath)+1]; 183457416Smarkm static char saved_user[sizeof(wtmp.ut_user)+1]; 183557416Smarkm 183657416Smarkm /* 183757416Smarkm * this little piece of code comes into play 183857416Smarkm * only when ptyreconnect is used to reconnect 183957416Smarkm * to an previous session. 184057416Smarkm * 184157416Smarkm * this is the only time when the 184257416Smarkm * "saved_jid != jid" code is executed. 184357416Smarkm */ 184457416Smarkm 184557416Smarkm if ( saved_jid && saved_jid != jid ) { 184657416Smarkm if (!path) { /* called from signal handler */ 184757416Smarkm pty_saved_jid = jid; 184857416Smarkm } else { 184957416Smarkm pty_saved_jid = saved_jid; 185057416Smarkm } 185157416Smarkm } 185257416Smarkm 185357416Smarkm if (path) { 1854178825Sdfr strlcpy(saved_path, path, sizeof(saved_path)); 1855178825Sdfr strlcpy(saved_user, user, sizeof(saved_user)); 185657416Smarkm } 185757416Smarkm if (saved_jid == 0) { 185857416Smarkm saved_jid = jid; 185957416Smarkm return(0); 186057416Smarkm } 186157416Smarkm 186257416Smarkm /* if the jid has changed, get the correct entry from the utmp file */ 186357416Smarkm 186457416Smarkm if ( saved_jid != jid ) { 186557416Smarkm struct utmp *utp = NULL; 186657416Smarkm struct utmp *jid_getutid(); 186757416Smarkm 186857416Smarkm utp = jid_getutid(pty_saved_jid); 186957416Smarkm 187057416Smarkm if (utp == 0) { 187157416Smarkm syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); 187257416Smarkm return(-1); 187357416Smarkm } 187457416Smarkm 187557416Smarkm cleantmpdir(jid, utp->ut_tpath, utp->ut_user); 187657416Smarkm return(1); 187757416Smarkm } 187857416Smarkm 187957416Smarkm cleantmpdir(jid, saved_path, saved_user); 188057416Smarkm return(1); 188157416Smarkm} 188257416Smarkm 188357416Smarkm/* 188457416Smarkm * Fork a child process to clean up the TMPDIR 188557416Smarkm */ 188657416Smarkmcleantmpdir(jid, tpath, user) 188757416Smarkm int jid; 188857416Smarkm char *tpath; 188957416Smarkm char *user; 189057416Smarkm{ 189157416Smarkm switch(fork()) { 189257416Smarkm case -1: 189357416Smarkm syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n", 189457416Smarkm tpath); 189557416Smarkm break; 189657416Smarkm case 0: 1897178825Sdfr execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, NULL); 189857416Smarkm syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n", 189957416Smarkm tpath, CLEANTMPCMD); 190057416Smarkm exit(1); 190157416Smarkm default: 190257416Smarkm /* 190357416Smarkm * Forget about child. We will exit, and 190457416Smarkm * /etc/init will pick it up. 190557416Smarkm */ 190657416Smarkm break; 190757416Smarkm } 190857416Smarkm} 190957416Smarkm#endif /* CRAY */ 191057416Smarkm#endif /* defined(PARENT_DOES_UTMP) */ 1911