Path: blob/main/crypto/heimdal/appl/telnet/telnetd/sys_term.c
34907 views
/*1* Copyright (c) 1989, 19932* The Regents of the University of California. All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12* 3. All advertising materials mentioning features or use of this software13* must display the following acknowledgement:14* This product includes software developed by the University of15* California, Berkeley and its contributors.16* 4. Neither the name of the University nor the names of its contributors17* may be used to endorse or promote products derived from this software18* without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF30* SUCH DAMAGE.31*/3233#include "telnetd.h"3435RCSID("$Id$");3637#if defined(_CRAY) || (defined(__hpux) && !defined(HAVE_UTMPX_H))38# define PARENT_DOES_UTMP39#endif4041#ifdef HAVE_UTMP_H42#include <utmp.h>43#endif4445#ifdef HAVE_UTMPX_H46#include <utmpx.h>47#endif4849#ifdef HAVE_UTMPX_H50struct utmpx wtmp;51#elif defined(HAVE_UTMP_H)52struct utmp wtmp;53#endif /* HAVE_UTMPX_H */5455#ifdef HAVE_STRUCT_UTMP_UT_HOST56int utmp_len = sizeof(wtmp.ut_host);57#else58int utmp_len = MaxHostNameLen;59#endif6061#ifndef UTMP_FILE62#ifdef _PATH_UTMP63#define UTMP_FILE _PATH_UTMP64#else65#define UTMP_FILE "/etc/utmp"66#endif67#endif6869/* really, mac os uses wtmpx (or asl) */70#ifdef __APPLE__71#undef _PATH_WTMP72#endif7374#if !defined(WTMP_FILE) && defined(_PATH_WTMP)75#define WTMP_FILE _PATH_WTMP76#endif7778#ifndef PARENT_DOES_UTMP79#ifdef WTMP_FILE80char wtmpf[] = WTMP_FILE;81#else82char wtmpf[] = "/usr/adm/wtmp";83#endif84char utmpf[] = UTMP_FILE;85#else /* PARENT_DOES_UTMP */86#ifdef WTMP_FILE87char wtmpf[] = WTMP_FILE;88#else89char wtmpf[] = "/etc/wtmp";90#endif91#endif /* PARENT_DOES_UTMP */9293#ifdef HAVE_TMPDIR_H94#include <tmpdir.h>95#endif /* CRAY */9697#if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY)98#include <sys/tty.h>99#endif100#ifdef t_erase101#undef t_erase102#undef t_kill103#undef t_intrc104#undef t_quitc105#undef t_startc106#undef t_stopc107#undef t_eofc108#undef t_brkc109#undef t_suspc110#undef t_dsuspc111#undef t_rprntc112#undef t_flushc113#undef t_werasc114#undef t_lnextc115#endif116117#ifdef HAVE_TERMIOS_H118#include <termios.h>119#else120#ifdef HAVE_TERMIO_H121#include <termio.h>122#endif123#endif124125#ifdef HAVE_UTIL_H126#include <util.h>127#endif128#ifdef HAVE_LIBUTIL_H129#include <libutil.h>130#endif131132# ifndef TCSANOW133# ifdef TCSETS134# define TCSANOW TCSETS135# define TCSADRAIN TCSETSW136# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)137# else138# ifdef TCSETA139# define TCSANOW TCSETA140# define TCSADRAIN TCSETAW141# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)142# else143# define TCSANOW TIOCSETA144# define TCSADRAIN TIOCSETAW145# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)146# endif147# endif148# define tcsetattr(f, a, t) ioctl(f, a, t)149# define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \150(tp)->c_cflag |= (val)151# define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)152# ifdef CIBAUD153# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \154(tp)->c_cflag |= ((val)<<IBSHIFT)155# define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)156# else157# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \158(tp)->c_cflag |= (val)159# define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)160# endif161# endif /* TCSANOW */162struct termios termbuf, termbuf2; /* pty control structure */163# ifdef STREAMSPTY164static int ttyfd = -1;165int really_stream = 0;166# else167#define really_stream 0168# endif169170const char *new_login = _PATH_LOGIN;171172/*173* init_termbuf()174* copy_termbuf(cp)175* set_termbuf()176*177* These three routines are used to get and set the "termbuf" structure178* to and from the kernel. init_termbuf() gets the current settings.179* copy_termbuf() hands in a new "termbuf" to write to the kernel, and180* set_termbuf() writes the structure into the kernel.181*/182183void184init_termbuf(void)185{186# ifdef STREAMSPTY187if (really_stream)188tcgetattr(ttyfd, &termbuf);189else190# endif191tcgetattr(ourpty, &termbuf);192termbuf2 = termbuf;193}194195void196set_termbuf(void)197{198/*199* Only make the necessary changes.200*/201if (memcmp(&termbuf, &termbuf2, sizeof(termbuf))) {202# ifdef STREAMSPTY203if (really_stream)204tcsetattr(ttyfd, TCSANOW, &termbuf);205else206# endif207tcsetattr(ourpty, TCSANOW, &termbuf);208}209}210211212/*213* spcset(func, valp, valpp)214*215* This function takes various special characters (func), and216* sets *valp to the current value of that character, and217* *valpp to point to where in the "termbuf" structure that218* value is kept.219*220* It returns the SLC_ level of support for this function.221*/222223224int225spcset(int func, cc_t *valp, cc_t **valpp)226{227228#define setval(a, b) *valp = termbuf.c_cc[a]; \229*valpp = &termbuf.c_cc[a]; \230return(b);231#define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);232233switch(func) {234case SLC_EOF:235setval(VEOF, SLC_VARIABLE);236case SLC_EC:237setval(VERASE, SLC_VARIABLE);238case SLC_EL:239setval(VKILL, SLC_VARIABLE);240case SLC_IP:241setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);242case SLC_ABORT:243setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);244case SLC_XON:245#ifdef VSTART246setval(VSTART, SLC_VARIABLE);247#else248defval(0x13);249#endif250case SLC_XOFF:251#ifdef VSTOP252setval(VSTOP, SLC_VARIABLE);253#else254defval(0x11);255#endif256case SLC_EW:257#ifdef VWERASE258setval(VWERASE, SLC_VARIABLE);259#else260defval(0);261#endif262case SLC_RP:263#ifdef VREPRINT264setval(VREPRINT, SLC_VARIABLE);265#else266defval(0);267#endif268case SLC_LNEXT:269#ifdef VLNEXT270setval(VLNEXT, SLC_VARIABLE);271#else272defval(0);273#endif274case SLC_AO:275#if !defined(VDISCARD) && defined(VFLUSHO)276# define VDISCARD VFLUSHO277#endif278#ifdef VDISCARD279setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);280#else281defval(0);282#endif283case SLC_SUSP:284#ifdef VSUSP285setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);286#else287defval(0);288#endif289#ifdef VEOL290case SLC_FORW1:291setval(VEOL, SLC_VARIABLE);292#endif293#ifdef VEOL2294case SLC_FORW2:295setval(VEOL2, SLC_VARIABLE);296#endif297case SLC_AYT:298#ifdef VSTATUS299setval(VSTATUS, SLC_VARIABLE);300#else301defval(0);302#endif303304case SLC_BRK:305case SLC_SYNCH:306case SLC_EOR:307defval(0);308309default:310*valp = 0;311*valpp = 0;312return(SLC_NOSUPPORT);313}314}315316#ifdef _CRAY317/*318* getnpty()319*320* Return the number of pty's configured into the system.321*/322int323getnpty()324{325#ifdef _SC_CRAY_NPTY326int numptys;327328if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)329return numptys;330else331#endif /* _SC_CRAY_NPTY */332return 128;333}334#endif /* CRAY */335336/*337* getpty()338*339* Allocate a pty. As a side effect, the external character340* array "line" contains the name of the slave side.341*342* Returns the file descriptor of the opened pty.343*/344345static int ptyslavefd = -1;346347static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";348char *line = Xline;349350#ifdef _CRAY351char myline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";352#endif /* CRAY */353354#if !defined(HAVE_PTSNAME) && defined(STREAMSPTY)355static char *ptsname(int fd)356{357#ifdef HAVE_TTYNAME358return ttyname(fd);359#else360return NULL;361#endif362}363#endif364365int getpty(int *ptynum)366{367#if defined(HAVE_OPENPTY) || defined(__linux) || defined(__osf__) /* XXX */368{369int master;370int slave;371if(openpty(&master, &slave, line, 0, 0) == 0){372ptyslavefd = slave;373return master;374}375}376#endif /* HAVE_OPENPTY .... */377#ifdef HAVE__GETPTY378{379int master;380char *p;381p = _getpty(&master, O_RDWR, 0600, 1);382if(p == NULL)383return -1;384strlcpy(line, p, sizeof(Xline));385return master;386}387#endif388389#ifdef STREAMSPTY390{391char *clone[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm",392"/dev/ptym/clone", 0 };393394char **q;395int p;396for(q=clone; *q; q++){397p=open(*q, O_RDWR);398if(p >= 0){399#ifdef HAVE_GRANTPT400grantpt(p);401#endif402#ifdef HAVE_UNLOCKPT403unlockpt(p);404#endif405strlcpy(line, ptsname(p), sizeof(Xline));406really_stream = 1;407return p;408}409}410}411#endif /* STREAMSPTY */412#ifndef _CRAY413{414int p;415char *cp, *p1, *p2;416int i;417418#ifndef __hpux419snprintf(line, sizeof(Xline), "/dev/ptyXX");420p1 = &line[8];421p2 = &line[9];422#else423snprintf(line, sizeof(Xline), "/dev/ptym/ptyXX");424p1 = &line[13];425p2 = &line[14];426#endif427428429for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {430struct stat stb;431432*p1 = *cp;433*p2 = '0';434/*435* This stat() check is just to keep us from436* looping through all 256 combinations if there437* aren't that many ptys available.438*/439if (stat(line, &stb) < 0)440break;441for (i = 0; i < 16; i++) {442*p2 = "0123456789abcdef"[i];443p = open(line, O_RDWR);444if (p > 0) {445#if SunOS == 40446int dummy;447#endif448449#ifndef __hpux450line[5] = 't';451#else452for (p1 = &line[8]; *p1; p1++)453*p1 = *(p1+1);454line[9] = 't';455#endif456chown(line, 0, 0);457chmod(line, 0600);458#if SunOS == 40459if (ioctl(p, TIOCGPGRP, &dummy) == 0460|| errno != EIO) {461chmod(line, 0666);462close(p);463line[5] = 'p';464} else465#endif /* SunOS == 40 */466return(p);467}468}469}470}471#else /* CRAY */472{473extern lowpty, highpty;474struct stat sb;475int p;476477for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {478snprintf(myline, sizeof(myline), "/dev/pty/%03d", *ptynum);479p = open(myline, 2);480if (p < 0)481continue;482snprintf(line, sizeof(Xline), "/dev/ttyp%03d", *ptynum);483/*484* Here are some shenanigans to make sure that there485* are no listeners lurking on the line.486*/487if(stat(line, &sb) < 0) {488close(p);489continue;490}491if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {492chown(line, 0, 0);493chmod(line, 0600);494close(p);495p = open(myline, 2);496if (p < 0)497continue;498}499/*500* Now it should be safe...check for accessability.501*/502if (access(line, 6) == 0)503return(p);504else {505/* no tty side to pty so skip it */506close(p);507}508}509}510#endif /* CRAY */511return(-1);512}513514515int516tty_isecho(void)517{518return (termbuf.c_lflag & ECHO);519}520521int522tty_flowmode(void)523{524return((termbuf.c_iflag & IXON) ? 1 : 0);525}526527int528tty_restartany(void)529{530return((termbuf.c_iflag & IXANY) ? 1 : 0);531}532533void534tty_setecho(int on)535{536if (on)537termbuf.c_lflag |= ECHO;538else539termbuf.c_lflag &= ~ECHO;540}541542int543tty_israw(void)544{545return(!(termbuf.c_lflag & ICANON));546}547548void549tty_binaryin(int on)550{551if (on) {552termbuf.c_iflag &= ~ISTRIP;553} else {554termbuf.c_iflag |= ISTRIP;555}556}557558void559tty_binaryout(int on)560{561if (on) {562termbuf.c_cflag &= ~(CSIZE|PARENB);563termbuf.c_cflag |= CS8;564termbuf.c_oflag &= ~OPOST;565} else {566termbuf.c_cflag &= ~CSIZE;567termbuf.c_cflag |= CS7|PARENB;568termbuf.c_oflag |= OPOST;569}570}571572int573tty_isbinaryin(void)574{575return(!(termbuf.c_iflag & ISTRIP));576}577578int579tty_isbinaryout(void)580{581return(!(termbuf.c_oflag&OPOST));582}583584585int586tty_issofttab(void)587{588# ifdef OXTABS589return (termbuf.c_oflag & OXTABS);590# endif591# ifdef TABDLY592return ((termbuf.c_oflag & TABDLY) == TAB3);593# endif594}595596void597tty_setsofttab(int on)598{599if (on) {600# ifdef OXTABS601termbuf.c_oflag |= OXTABS;602# endif603# ifdef TABDLY604termbuf.c_oflag &= ~TABDLY;605termbuf.c_oflag |= TAB3;606# endif607} else {608# ifdef OXTABS609termbuf.c_oflag &= ~OXTABS;610# endif611# ifdef TABDLY612termbuf.c_oflag &= ~TABDLY;613termbuf.c_oflag |= TAB0;614# endif615}616}617618int619tty_islitecho(void)620{621# ifdef ECHOCTL622return (!(termbuf.c_lflag & ECHOCTL));623# endif624# ifdef TCTLECH625return (!(termbuf.c_lflag & TCTLECH));626# endif627# if !defined(ECHOCTL) && !defined(TCTLECH)628return (0); /* assumes ctl chars are echoed '^x' */629# endif630}631632void633tty_setlitecho(int on)634{635# ifdef ECHOCTL636if (on)637termbuf.c_lflag &= ~ECHOCTL;638else639termbuf.c_lflag |= ECHOCTL;640# endif641# ifdef TCTLECH642if (on)643termbuf.c_lflag &= ~TCTLECH;644else645termbuf.c_lflag |= TCTLECH;646# endif647}648649int650tty_iscrnl(void)651{652return (termbuf.c_iflag & ICRNL);653}654655/*656* Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).657*/658#if B4800 != 4800659#define DECODE_BAUD660#endif661662#ifdef DECODE_BAUD663664/*665* A table of available terminal speeds666*/667struct termspeeds {668int speed;669int value;670} termspeeds[] = {671{ 0, B0 }, { 50, B50 }, { 75, B75 },672{ 110, B110 }, { 134, B134 }, { 150, B150 },673{ 200, B200 }, { 300, B300 }, { 600, B600 },674{ 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },675{ 4800, B4800 },676#ifdef B7200677{ 7200, B7200 },678#endif679{ 9600, B9600 },680#ifdef B14400681{ 14400, B14400 },682#endif683#ifdef B19200684{ 19200, B19200 },685#endif686#ifdef B28800687{ 28800, B28800 },688#endif689#ifdef B38400690{ 38400, B38400 },691#endif692#ifdef B57600693{ 57600, B57600 },694#endif695#ifdef B115200696{ 115200, B115200 },697#endif698#ifdef B230400699{ 230400, B230400 },700#endif701{ -1, 0 }702};703#endif /* DECODE_BUAD */704705void706tty_tspeed(int val)707{708#ifdef DECODE_BAUD709struct termspeeds *tp;710711for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)712;713if (tp->speed == -1) /* back up to last valid value */714--tp;715cfsetospeed(&termbuf, tp->value);716#else /* DECODE_BUAD */717cfsetospeed(&termbuf, val);718#endif /* DECODE_BUAD */719}720721void722tty_rspeed(int val)723{724#ifdef DECODE_BAUD725struct termspeeds *tp;726727for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)728;729if (tp->speed == -1) /* back up to last valid value */730--tp;731cfsetispeed(&termbuf, tp->value);732#else /* DECODE_BAUD */733cfsetispeed(&termbuf, val);734#endif /* DECODE_BAUD */735}736737#ifdef PARENT_DOES_UTMP738extern struct utmp wtmp;739extern char wtmpf[];740741extern void utmp_sig_init (void);742extern void utmp_sig_reset (void);743extern void utmp_sig_wait (void);744extern void utmp_sig_notify (int);745# endif /* PARENT_DOES_UTMP */746747#ifdef STREAMSPTY748749/* I_FIND seems to live a life of its own */750static int my_find(int fd, char *module)751{752#if defined(I_FIND) && defined(I_LIST)753static int flag;754static struct str_list sl;755int n;756int i;757758if(!flag){759n = ioctl(fd, I_LIST, 0);760if(n < 0){761perror("ioctl(fd, I_LIST, 0)");762return -1;763}764sl.sl_modlist=(struct str_mlist*)malloc(n * sizeof(struct str_mlist));765sl.sl_nmods = n;766n = ioctl(fd, I_LIST, &sl);767if(n < 0){768perror("ioctl(fd, I_LIST, n)");769return -1;770}771flag = 1;772}773774for(i=0; i<sl.sl_nmods; i++)775if(!strcmp(sl.sl_modlist[i].l_name, module))776return 1;777#endif778return 0;779}780781static void maybe_push_modules(int fd, char **modules)782{783char **p;784int err;785786for(p=modules; *p; p++){787err = my_find(fd, *p);788if(err == 1)789break;790if(err < 0 && errno != EINVAL)791fatalperror(net, "my_find()");792/* module not pushed or does not exist */793}794/* p points to null or to an already pushed module, now push all795modules before this one */796797for(p--; p >= modules; p--){798err = ioctl(fd, I_PUSH, *p);799if(err < 0 && errno != EINVAL)800fatalperror(net, "I_PUSH");801}802}803#endif804805/*806* getptyslave()807*808* Open the slave side of the pty, and do any initialization809* that is necessary. The return value is a file descriptor810* for the slave side.811*/812void getptyslave(void)813{814int t = -1;815816struct winsize ws;817/*818* Opening the slave side may cause initilization of the819* kernel tty structure. We need remember the state of820* if linemode was turned on821* terminal window size822* terminal speed823* so that we can re-set them if we need to.824*/825826827/*828* Make sure that we don't have a controlling tty, and829* that we are the session (process group) leader.830*/831832#ifdef HAVE_SETSID833if(setsid()<0)834fatalperror(net, "setsid()");835#else836# ifdef TIOCNOTTY837t = open(_PATH_TTY, O_RDWR);838if (t >= 0) {839ioctl(t, TIOCNOTTY, (char *)0);840close(t);841}842# endif843#endif844845# ifdef PARENT_DOES_UTMP846/*847* Wait for our parent to get the utmp stuff to get done.848*/849utmp_sig_wait();850# endif851852t = cleanopen(line);853if (t < 0)854fatalperror(net, line);855856#ifdef STREAMSPTY857ttyfd = t;858859860/*861* Not all systems have (or need) modules ttcompat and pckt so862* don't flag it as a fatal error if they don't exist.863*/864865if (really_stream)866{867/* these are the streams modules that we want pushed. note868that they are in reverse order, ptem will be pushed869first. maybe_push_modules() will try to push all modules870before the first one that isn't already pushed. i.e if871ldterm is pushed, only ttcompat will be attempted.872873all this is because we don't know which modules are874available, and we don't know which modules are already875pushed (via autopush, for instance).876877*/878879char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL };880char *ptymodules[] = { "pckt", NULL };881882maybe_push_modules(t, ttymodules);883maybe_push_modules(ourpty, ptymodules);884}885#endif886/*887* set up the tty modes as we like them to be.888*/889init_termbuf();890# ifdef TIOCSWINSZ891if (def_row || def_col) {892memset(&ws, 0, sizeof(ws));893ws.ws_col = def_col;894ws.ws_row = def_row;895ioctl(t, TIOCSWINSZ, (char *)&ws);896}897# endif898899/*900* Settings for sgtty based systems901*/902903/*904* Settings for UNICOS (and HPUX)905*/906# if defined(_CRAY) || defined(__hpux)907termbuf.c_oflag = OPOST|ONLCR|TAB3;908termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;909termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;910termbuf.c_cflag = EXTB|HUPCL|CS8;911# endif912913/*914* Settings for all other termios/termio based915* systems, other than 4.4BSD. In 4.4BSD the916* kernel does the initial terminal setup.917*/918# if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43)919# ifndef OXTABS920# define OXTABS 0921# endif922termbuf.c_lflag |= ECHO;923termbuf.c_oflag |= ONLCR|OXTABS;924termbuf.c_iflag |= ICRNL;925termbuf.c_iflag &= ~IXOFF;926# endif927tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);928tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);929930/*931* Set the tty modes, and make this our controlling tty.932*/933set_termbuf();934if (login_tty(t) == -1)935fatalperror(net, "login_tty");936if (net > 2)937close(net);938if (ourpty > 2) {939close(ourpty);940ourpty = -1;941}942}943944#ifndef O_NOCTTY945#define O_NOCTTY 0946#endif947/*948* Open the specified slave side of the pty,949* making sure that we have a clean tty.950*/951952int cleanopen(char *line)953{954int t;955956if (ptyslavefd != -1)957return ptyslavefd;958959#ifdef STREAMSPTY960if (!really_stream)961#endif962{963/*964* Make sure that other people can't open the965* slave side of the connection.966*/967chown(line, 0, 0);968chmod(line, 0600);969}970971#ifdef HAVE_REVOKE972revoke(line);973#endif974975t = open(line, O_RDWR|O_NOCTTY);976977if (t < 0)978return(-1);979980/*981* Hangup anybody else using this ttyp, then reopen it for982* ourselves.983*/984# if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)985signal(SIGHUP, SIG_IGN);986#ifdef HAVE_VHANGUP987vhangup();988#else989#endif990signal(SIGHUP, SIG_DFL);991t = open(line, O_RDWR|O_NOCTTY);992if (t < 0)993return(-1);994# endif995# if defined(_CRAY) && defined(TCVHUP)996{997int i;998signal(SIGHUP, SIG_IGN);999ioctl(t, TCVHUP, (char *)0);1000signal(SIGHUP, SIG_DFL);10011002i = open(line, O_RDWR);10031004if (i < 0)1005return(-1);1006close(t);1007t = i;1008}1009# endif /* defined(CRAY) && defined(TCVHUP) */1010return(t);1011}10121013#if !defined(BSD4_4)10141015int login_tty(int t)1016{1017/* Dont need to set this as the controlling PTY on steams sockets,1018* don't abort on failure. */1019# if defined(TIOCSCTTY) && !defined(__hpux)1020if (ioctl(t, TIOCSCTTY, (char *)0) < 0 && !really_stream)1021fatalperror(net, "ioctl(sctty)");1022# ifdef _CRAY1023/*1024* Close the hard fd to /dev/ttypXXX, and re-open through1025* the indirect /dev/tty interface.1026*/1027close(t);1028if ((t = open("/dev/tty", O_RDWR)) < 0)1029fatalperror(net, "open(/dev/tty)");1030# endif1031# else1032/*1033* We get our controlling tty assigned as a side-effect1034* of opening up a tty device. But on BSD based systems,1035* this only happens if our process group is zero. The1036* setsid() call above may have set our pgrp, so clear1037* it out before opening the tty...1038*/1039#ifdef HAVE_SETPGID1040setpgid(0, 0);1041#else1042setpgrp(0, 0); /* if setpgid isn't available, setpgrp1043probably takes arguments */1044#endif1045close(open(line, O_RDWR));1046# endif1047if (t != 0)1048dup2(t, 0);1049if (t != 1)1050dup2(t, 1);1051if (t != 2)1052dup2(t, 2);1053if (t > 2)1054close(t);1055return(0);1056}1057#endif /* BSD <= 43 */10581059/*1060* This comes from ../../bsd/tty.c and should not really be here.1061*/10621063/*1064* Clean the tty name. Return a pointer to the cleaned version.1065*/10661067static char * clean_ttyname (char *) __attribute__((unused));10681069static char *1070clean_ttyname (char *tty)1071{1072char *res = tty;10731074if (strncmp (res, _PATH_DEV, strlen(_PATH_DEV)) == 0)1075res += strlen(_PATH_DEV);1076if (strncmp (res, "pty/", 4) == 0)1077res += 4;1078if (strncmp (res, "ptym/", 5) == 0)1079res += 5;1080return res;1081}10821083/*1084* Generate a name usable as an `ut_id', typically without `tty'.1085*/10861087#ifdef HAVE_STRUCT_UTMP_UT_ID1088static char *1089make_id (char *tty)1090{1091char *res = tty;10921093if (strncmp (res, "pts/", 4) == 0)1094res += 4;1095if (strncmp (res, "tty", 3) == 0)1096res += 3;1097return res;1098}1099#endif11001101/*1102* startslave(host)1103*1104* Given a hostname, do whatever1105* is necessary to startup the login process on the slave side of the pty.1106*/11071108/* ARGSUSED */1109void1110startslave(const char *host, const char *utmp_host,1111int autologin, char *autoname)1112{1113int i;11141115#ifdef AUTHENTICATION1116if (!autoname || !autoname[0])1117autologin = 0;11181119if (autologin < auth_level) {1120fatal(net, "Authorization failed");1121exit(1);1122}1123#endif11241125{1126char *tbuf =1127"\r\n*** Connection not encrypted! "1128"Communication may be eavesdropped. ***\r\n";1129#ifdef ENCRYPTION1130if (!no_warn && (encrypt_output == 0 || decrypt_input == 0))1131#endif1132writenet(tbuf, strlen(tbuf));1133}1134# ifdef PARENT_DOES_UTMP1135utmp_sig_init();1136# endif /* PARENT_DOES_UTMP */11371138if ((i = fork()) < 0)1139fatalperror(net, "fork");1140if (i) {1141# ifdef PARENT_DOES_UTMP1142/*1143* Cray parent will create utmp entry for child and send1144* signal to child to tell when done. Child waits for signal1145* before doing anything important.1146*/1147int pid = i;1148void sigjob (int);11491150setpgrp();1151utmp_sig_reset(); /* reset handler to default */1152/*1153* Create utmp entry for child1154*/1155wtmp.ut_time = time(NULL);1156wtmp.ut_type = LOGIN_PROCESS;1157wtmp.ut_pid = pid;1158strncpy(wtmp.ut_user, "LOGIN", sizeof(wtmp.ut_user));1159strncpy(wtmp.ut_host, utmp_host, sizeof(wtmp.ut_host));1160strncpy(wtmp.ut_line, clean_ttyname(line), sizeof(wtmp.ut_line));1161#ifdef HAVE_STRUCT_UTMP_UT_ID1162strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id));1163#endif11641165pututline(&wtmp);1166endutent();1167if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {1168write(i, &wtmp, sizeof(struct utmp));1169close(i);1170}1171#ifdef _CRAY1172signal(WJSIGNAL, sigjob);1173#endif1174utmp_sig_notify(pid);1175# endif /* PARENT_DOES_UTMP */1176} else {1177getptyslave();1178#if defined(DCE)1179/* if we authenticated via K5, try and join the PAG */1180kerberos5_dfspag();1181#endif1182start_login(host, autologin, autoname);1183/*NOTREACHED*/1184}1185}11861187char *envinit[3];1188#if !HAVE_DECL_ENVIRON1189extern char **environ;1190#endif11911192void1193init_env(void)1194{1195char **envp;11961197envp = envinit;1198if ((*envp = getenv("TZ")))1199*envp++ -= 3;1200#if defined(_CRAY) || defined(__hpux)1201else1202*envp++ = "TZ=GMT0";1203#endif1204*envp = 0;1205environ = envinit;1206}12071208/*1209* scrub_env()1210*1211* We only accept the environment variables listed below.1212*/12131214static void1215scrub_env(void)1216{1217static const char *reject[] = {1218"TERMCAP=/",1219NULL1220};12211222static const char *accept[] = {1223"XAUTH=", "XAUTHORITY=", "DISPLAY=",1224"TERM=",1225"EDITOR=",1226"PAGER=",1227"PRINTER=",1228"LOGNAME=",1229"POSIXLY_CORRECT=",1230"TERMCAP=",1231NULL1232};12331234char **cpp, **cpp2;1235const char **p;12361237for (cpp2 = cpp = environ; *cpp; cpp++) {1238int reject_it = 0;12391240for(p = reject; *p; p++)1241if(strncmp(*cpp, *p, strlen(*p)) == 0) {1242reject_it = 1;1243break;1244}1245if (reject_it)1246continue;12471248for(p = accept; *p; p++)1249if(strncmp(*cpp, *p, strlen(*p)) == 0)1250break;1251if(*p != NULL)1252*cpp2++ = *cpp;1253}1254*cpp2 = NULL;1255}125612571258struct arg_val {1259int size;1260int argc;1261char **argv;1262};12631264static void addarg(struct arg_val*, const char*);12651266/*1267* start_login(host)1268*1269* Assuming that we are now running as a child processes, this1270* function will turn us into the login process.1271*/12721273void1274start_login(const char *host, int autologin, char *name)1275{1276struct arg_val argv;1277char *user;1278int save_errno;12791280#ifdef ENCRYPTION1281encrypt_output = NULL;1282decrypt_input = NULL;1283#endif12841285#ifdef HAVE_UTMPX_H1286{1287int pid = getpid();1288struct utmpx utmpx;1289struct timeval tv;1290char *clean_tty;12911292/*1293* Create utmp entry for child1294*/12951296clean_tty = clean_ttyname(line);1297memset(&utmpx, 0, sizeof(utmpx));1298strncpy(utmpx.ut_user, ".telnet", sizeof(utmpx.ut_user));1299strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));1300#ifdef HAVE_STRUCT_UTMP_UT_ID1301strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id));1302#endif1303utmpx.ut_pid = pid;13041305utmpx.ut_type = LOGIN_PROCESS;13061307gettimeofday (&tv, NULL);1308utmpx.ut_tv.tv_sec = tv.tv_sec;1309utmpx.ut_tv.tv_usec = tv.tv_usec;13101311if (pututxline(&utmpx) == NULL)1312fatal(net, "pututxline failed");1313}1314#endif13151316scrub_env();13171318/*1319* -h : pass on name of host.1320* WARNING: -h is accepted by login if and only if1321* getuid() == 0.1322* -p : don't clobber the environment (so terminal type stays set).1323*1324* -f : force this login, he has already been authenticated1325*/13261327/* init argv structure */1328argv.size=0;1329argv.argc=0;1330argv.argv=malloc(0); /*so we can call realloc later */1331addarg(&argv, "login");1332addarg(&argv, "-h");1333addarg(&argv, host);1334addarg(&argv, "-p");1335if(name && name[0])1336user = name;1337else1338user = getenv("USER");1339#ifdef AUTHENTICATION1340if (auth_level < 0 || autologin != AUTH_VALID) {1341if(!no_warn) {1342printf("User not authenticated. ");1343if (require_otp)1344printf("Using one-time password\r\n");1345else1346printf("Using plaintext username and password\r\n");1347}1348if (require_otp) {1349addarg(&argv, "-a");1350addarg(&argv, "otp");1351}1352if(log_unauth)1353syslog(LOG_INFO, "unauthenticated access from %s (%s)",1354host, user ? user : "unknown user");1355}1356if (auth_level >= 0 && autologin == AUTH_VALID)1357addarg(&argv, "-f");1358#endif1359if(user){1360addarg(&argv, "--");1361addarg(&argv, strdup(user));1362}1363if (getenv("USER")) {1364/*1365* Assume that login will set the USER variable1366* correctly. For SysV systems, this means that1367* USER will no longer be set, just LOGNAME by1368* login. (The problem is that if the auto-login1369* fails, and the user then specifies a different1370* account name, he can get logged in with both1371* LOGNAME and USER in his environment, but the1372* USER value will be wrong.1373*/1374unsetenv("USER");1375}1376closelog();1377/*1378* This sleep(1) is in here so that telnetd can1379* finish up with the tty. There's a race condition1380* the login banner message gets lost...1381*/1382sleep(1);13831384execv(new_login, argv.argv);1385save_errno = errno;1386syslog(LOG_ERR, "%s: %m", new_login);1387fatalperror_errno(net, new_login, save_errno);1388/*NOTREACHED*/1389}13901391static void1392addarg(struct arg_val *argv, const char *val)1393{1394if(argv->size <= argv->argc+1) {1395argv->argv = realloc(argv->argv, sizeof(char*) * (argv->size + 10));1396if (argv->argv == NULL)1397fatal (net, "realloc: out of memory");1398argv->size+=10;1399}1400if((argv->argv[argv->argc++] = strdup(val)) == NULL)1401fatal (net, "strdup: out of memory");1402argv->argv[argv->argc] = NULL;1403}140414051406/*1407* rmut()1408*1409* This is the function called by cleanup() to1410* remove the utmp entry for this person.1411*/14121413#ifdef HAVE_UTMPX_H1414static void1415rmut(void)1416{1417struct utmpx utmpx, *non_save_utxp;1418char *clean_tty = clean_ttyname(line);14191420/*1421* This updates the utmpx and utmp entries and make a wtmp/x entry1422*/14231424setutxent();1425memset(&utmpx, 0, sizeof(utmpx));1426strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));1427utmpx.ut_type = LOGIN_PROCESS;1428non_save_utxp = getutxline(&utmpx);1429if (non_save_utxp) {1430struct utmpx *utxp;1431struct timeval tv;1432char user0;14331434utxp = malloc(sizeof(struct utmpx));1435*utxp = *non_save_utxp;1436user0 = utxp->ut_user[0];1437utxp->ut_user[0] = '\0';1438utxp->ut_type = DEAD_PROCESS;1439#ifdef HAVE_STRUCT_UTMPX_UT_EXIT1440#ifdef _STRUCT___EXIT_STATUS1441utxp->ut_exit.__e_termination = 0;1442utxp->ut_exit.__e_exit = 0;1443#elif defined(__osf__) /* XXX */1444utxp->ut_exit.ut_termination = 0;1445utxp->ut_exit.ut_exit = 0;1446#else1447utxp->ut_exit.e_termination = 0;1448utxp->ut_exit.e_exit = 0;1449#endif1450#endif1451gettimeofday (&tv, NULL);1452utxp->ut_tv.tv_sec = tv.tv_sec;1453utxp->ut_tv.tv_usec = tv.tv_usec;14541455pututxline(utxp);1456#ifdef WTMPX_FILE1457utxp->ut_user[0] = user0;1458updwtmpx(WTMPX_FILE, utxp);1459#elif defined(WTMP_FILE)1460/* This is a strange system with a utmpx and a wtmp! */1461{1462int f = open(wtmpf, O_WRONLY|O_APPEND);1463struct utmp wtmp;1464if (f >= 0) {1465strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));1466strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));1467#ifdef HAVE_STRUCT_UTMP_UT_HOST1468strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));1469#endif1470wtmp.ut_time = time(NULL);1471write(f, &wtmp, sizeof(wtmp));1472close(f);1473}1474}1475#endif1476free (utxp);1477}1478endutxent();1479} /* end of rmut */1480#endif14811482#if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 431483static void1484rmut(void)1485{1486int f;1487int found = 0;1488struct utmp *u, *utmp;1489int nutmp;1490struct stat statbf;1491char *clean_tty = clean_ttyname(line);14921493f = open(utmpf, O_RDWR);1494if (f >= 0) {1495fstat(f, &statbf);1496utmp = (struct utmp *)malloc((unsigned)statbf.st_size);1497if (!utmp)1498syslog(LOG_ERR, "utmp malloc failed");1499if (statbf.st_size && utmp) {1500nutmp = read(f, utmp, (int)statbf.st_size);1501nutmp /= sizeof(struct utmp);15021503for (u = utmp ; u < &utmp[nutmp] ; u++) {1504if (strncmp(u->ut_line,1505clean_tty,1506sizeof(u->ut_line)) ||1507u->ut_name[0]==0)1508continue;1509lseek(f, ((long)u)-((long)utmp), L_SET);1510strncpy(u->ut_name, "", sizeof(u->ut_name));1511#ifdef HAVE_STRUCT_UTMP_UT_HOST1512strncpy(u->ut_host, "", sizeof(u->ut_host));1513#endif1514u->ut_time = time(NULL);1515write(f, u, sizeof(wtmp));1516found++;1517}1518}1519close(f);1520}1521if (found) {1522f = open(wtmpf, O_WRONLY|O_APPEND);1523if (f >= 0) {1524strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));1525strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));1526#ifdef HAVE_STRUCT_UTMP_UT_HOST1527strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));1528#endif1529wtmp.ut_time = time(NULL);1530write(f, &wtmp, sizeof(wtmp));1531close(f);1532}1533}1534chmod(line, 0666);1535chown(line, 0, 0);1536line[strlen("/dev/")] = 'p';1537chmod(line, 0666);1538chown(line, 0, 0);1539} /* end of rmut */1540#endif /* CRAY */15411542#if defined(__hpux) && !defined(HAVE_UTMPX_H)1543static void1544rmut (char *line)1545{1546struct utmp utmp;1547struct utmp *utptr;1548int fd; /* for /etc/wtmp */15491550utmp.ut_type = USER_PROCESS;1551strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line));1552setutent();1553utptr = getutline(&utmp);1554/* write it out only if it exists */1555if (utptr) {1556utptr->ut_type = DEAD_PROCESS;1557utptr->ut_time = time(NULL);1558pututline(utptr);1559/* set wtmp entry if wtmp file exists */1560if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {1561write(fd, utptr, sizeof(utmp));1562close(fd);1563}1564}1565endutent();15661567chmod(line, 0666);1568chown(line, 0, 0);1569line[14] = line[13];1570line[13] = line[12];1571line[8] = 'm';1572line[9] = '/';1573line[10] = 'p';1574line[11] = 't';1575line[12] = 'y';1576chmod(line, 0666);1577chown(line, 0, 0);1578}1579#endif15801581/*1582* cleanup()1583*1584* This is the routine to call when we are all through, to1585* clean up anything that needs to be cleaned up.1586*/15871588#ifdef PARENT_DOES_UTMP15891590void1591cleanup(int sig)1592{1593#ifdef _CRAY1594static int incleanup = 0;1595int t;1596int child_status; /* status of child process as returned by waitpid */1597int flags = WNOHANG|WUNTRACED;15981599/*1600* 1: Pick up the zombie, if we are being called1601* as the signal handler.1602* 2: If we are a nested cleanup(), return.1603* 3: Try to clean up TMPDIR.1604* 4: Fill in utmp with shutdown of process.1605* 5: Close down the network and pty connections.1606* 6: Finish up the TMPDIR cleanup, if needed.1607*/1608if (sig == SIGCHLD) {1609while (waitpid(-1, &child_status, flags) > 0)1610; /* VOID */1611/* Check if the child process was stopped1612* rather than exited. We want cleanup only if1613* the child has died.1614*/1615if (WIFSTOPPED(child_status)) {1616return;1617}1618}1619t = sigblock(sigmask(SIGCHLD));1620if (incleanup) {1621sigsetmask(t);1622return;1623}1624incleanup = 1;1625sigsetmask(t);16261627t = cleantmp(&wtmp);1628setutent(); /* just to make sure */1629#endif /* CRAY */1630rmut(line);1631close(ourpty);1632shutdown(net, 2);1633#ifdef _CRAY1634if (t == 0)1635cleantmp(&wtmp);1636#endif /* CRAY */1637exit(1);1638}16391640#else /* PARENT_DOES_UTMP */16411642void1643cleanup(int sig)1644{1645#if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)1646rmut();1647#ifdef HAVE_VHANGUP1648#ifndef __sgi1649vhangup(); /* XXX */1650#endif1651#endif1652#else1653char *p;16541655p = line + sizeof("/dev/") - 1;1656if (logout(p))1657logwtmp(p, "", "");1658chmod(line, 0666);1659chown(line, 0, 0);1660*p = 'p';1661chmod(line, 0666);1662chown(line, 0, 0);1663#endif1664shutdown(net, 2);1665exit(1);1666}16671668#endif /* PARENT_DOES_UTMP */16691670#ifdef PARENT_DOES_UTMP1671/*1672* _utmp_sig_rcv1673* utmp_sig_init1674* utmp_sig_wait1675* These three functions are used to coordinate the handling of1676* the utmp file between the server and the soon-to-be-login shell.1677* The server actually creates the utmp structure, the child calls1678* utmp_sig_wait(), until the server calls utmp_sig_notify() and1679* signals the future-login shell to proceed.1680*/1681static int caught=0; /* NZ when signal intercepted */1682static void (*func)(); /* address of previous handler */16831684void1685_utmp_sig_rcv(sig)1686int sig;1687{1688caught = 1;1689signal(SIGUSR1, func);1690}16911692void1693utmp_sig_init()1694{1695/*1696* register signal handler for UTMP creation1697*/1698if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)1699fatalperror(net, "telnetd/signal");1700}17011702void1703utmp_sig_reset()1704{1705signal(SIGUSR1, func); /* reset handler to default */1706}17071708# ifdef __hpux1709# define sigoff() /* do nothing */1710# define sigon() /* do nothing */1711# endif17121713void1714utmp_sig_wait()1715{1716/*1717* Wait for parent to write our utmp entry.1718*/1719sigoff();1720while (caught == 0) {1721pause(); /* wait until we get a signal (sigon) */1722sigoff(); /* turn off signals while we check caught */1723}1724sigon(); /* turn on signals again */1725}17261727void1728utmp_sig_notify(pid)1729{1730kill(pid, SIGUSR1);1731}17321733#ifdef _CRAY1734static int gotsigjob = 0;17351736/*ARGSUSED*/1737void1738sigjob(sig)1739int sig;1740{1741int jid;1742struct jobtemp *jp;17431744while ((jid = waitjob(NULL)) != -1) {1745if (jid == 0) {1746return;1747}1748gotsigjob++;1749jobend(jid, NULL, NULL);1750}1751}17521753/*1754* jid_getutid:1755* called by jobend() before calling cleantmp()1756* to find the correct $TMPDIR to cleanup.1757*/17581759struct utmp *1760jid_getutid(jid)1761int jid;1762{1763struct utmp *cur = NULL;17641765setutent(); /* just to make sure */1766while (cur = getutent()) {1767if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {1768return(cur);1769}1770}17711772return(0);1773}17741775/*1776* Clean up the TMPDIR that login created.1777* The first time this is called we pick up the info1778* from the utmp. If the job has already gone away,1779* then we'll clean up and be done. If not, then1780* when this is called the second time it will wait1781* for the signal that the job is done.1782*/1783int1784cleantmp(wtp)1785struct utmp *wtp;1786{1787struct utmp *utp;1788static int first = 1;1789int mask, omask, ret;1790extern struct utmp *getutid (const struct utmp *_Id);179117921793mask = sigmask(WJSIGNAL);17941795if (first == 0) {1796omask = sigblock(mask);1797while (gotsigjob == 0)1798sigpause(omask);1799return(1);1800}1801first = 0;1802setutent(); /* just to make sure */18031804utp = getutid(wtp);1805if (utp == 0) {1806syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");1807return(-1);1808}1809/*1810* Nothing to clean up if the user shell was never started.1811*/1812if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)1813return(1);18141815/*1816* Block the WJSIGNAL while we are in jobend().1817*/1818omask = sigblock(mask);1819ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);1820sigsetmask(omask);1821return(ret);1822}18231824int1825jobend(jid, path, user)1826int jid;1827char *path;1828char *user;1829{1830static int saved_jid = 0;1831static int pty_saved_jid = 0;1832static char saved_path[sizeof(wtmp.ut_tpath)+1];1833static char saved_user[sizeof(wtmp.ut_user)+1];18341835/*1836* this little piece of code comes into play1837* only when ptyreconnect is used to reconnect1838* to an previous session.1839*1840* this is the only time when the1841* "saved_jid != jid" code is executed.1842*/18431844if ( saved_jid && saved_jid != jid ) {1845if (!path) { /* called from signal handler */1846pty_saved_jid = jid;1847} else {1848pty_saved_jid = saved_jid;1849}1850}18511852if (path) {1853strlcpy(saved_path, path, sizeof(saved_path));1854strlcpy(saved_user, user, sizeof(saved_user));1855}1856if (saved_jid == 0) {1857saved_jid = jid;1858return(0);1859}18601861/* if the jid has changed, get the correct entry from the utmp file */18621863if ( saved_jid != jid ) {1864struct utmp *utp = NULL;1865struct utmp *jid_getutid();18661867utp = jid_getutid(pty_saved_jid);18681869if (utp == 0) {1870syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");1871return(-1);1872}18731874cleantmpdir(jid, utp->ut_tpath, utp->ut_user);1875return(1);1876}18771878cleantmpdir(jid, saved_path, saved_user);1879return(1);1880}18811882/*1883* Fork a child process to clean up the TMPDIR1884*/1885cleantmpdir(jid, tpath, user)1886int jid;1887char *tpath;1888char *user;1889{1890switch(fork()) {1891case -1:1892syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",1893tpath);1894break;1895case 0:1896execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, NULL);1897syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",1898tpath, CLEANTMPCMD);1899exit(1);1900default:1901/*1902* Forget about child. We will exit, and1903* /etc/init will pick it up.1904*/1905break;1906}1907}1908#endif /* CRAY */1909#endif /* defined(PARENT_DOES_UTMP) */191019111912