1/* pty_unicos.c - routines to allocate ptys - for CRAY UNICOS 5.1 and 6.0 */
2
3/*
4
5Original by: Don Libes, NIST, 2/6/90
6Hacked for Unicos 5.1 by: Frank Terhaar-Yonkers, US EPA,  1/10/91
7Hacked for Unicos 6.0 by: Pete TerMaat, pete@willow.cray.com, 3/27/91
8
9Design and implementation of this program was paid for by U.S. tax
10dollars.  Therefore it is public domain.  However, the author and NIST
11would appreciate credit if this program or parts of it are used.
12
13*/
14
15#include "expect_cf.h"
16#include <stdio.h>
17#include <signal.h>
18
19#if defined(SIGCLD) && !defined(SIGCHLD)
20#define SIGCHLD SIGCLD
21#endif
22
23#ifdef HAVE_UNISTD_H
24#include <unistd.h>
25#else
26extern int fork(), execl(), wait();
27#endif
28#include <errno.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <sys/ioctl.h>
32#include <sys/file.h>
33#ifdef HAVE_SYS_FCNTL_H
34#  include <sys/fcntl.h>
35#else
36#  include <fcntl.h>
37#endif
38/*#if CRAY>=60*/
39#if defined(HAVE_TERMIOS)
40# include <sys/termios.h>
41#else
42# include <sys/termio.h>
43/*#endif /* 60 */*/
44#endif /* defined(HAVE_TERMIOS) */
45#if CRAY>=70 && defined(_CRAY2)
46#include <sys/session.h>
47#endif /* 70 */
48#include <sys/pty.h>
49#include <pwd.h>
50#include <utmp.h>
51#include <signal.h>
52#include "exp_tty_in.h"
53#include "exp_rename.h"
54
55#ifdef HAVE_SYSCONF_H
56#include <sys/sysconfig.h>
57#endif
58
59void expDiagLog();
60
61#ifndef TRUE
62#define TRUE 1
63#define FALSE 0
64#endif
65
66#ifndef MAXHOSTNAMELEN
67#define MAXHOSTNAMELEN 64
68#endif /* MAXHOSTNAMELEN */
69
70static char	linep[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
71static char	linet[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
72static int	lowpty;
73static int	highpty;
74static int	realuid;
75static int	realgid;
76static int 	*ptys;
77static char myname[32];
78static char hostname[MAXHOSTNAMELEN];
79char *exp_pty_slave_name;
80char *exp_pty_error;
81
82static void
83pty_stty(s,name)
84char *s;		/* args to stty */
85char *name;		/* name of pty */
86{
87#define MAX_ARGLIST 10240
88	char buf[MAX_ARGLIST];	/* overkill is easier */
89	RETSIGTYPE (*old)();	/* save old sigalarm handler */
90
91#ifdef STTY_READS_STDOUT
92	sprintf(buf,"%s %s > %s",STTY_BIN,s,name);
93#else
94	sprintf(buf,"%s %s < %s",STTY_BIN,s,name);
95#endif
96	old = signal(SIGCHLD, SIG_DFL);
97	system(buf);
98	signal(SIGCHLD, old);	/* restore signal handler */
99}
100
101int exp_dev_tty;	/* file descriptor to /dev/tty or -1 if none */
102static int knew_dev_tty;/* true if we had our hands on /dev/tty at any time */
103
104#ifdef TIOCGWINSZ
105static struct winsize winsize = {0, 0};
106#endif
107#if defined(TIOCGSIZE) && !defined(TIOCGWINSZ)
108static struct ttysize winsize = {0, 0};
109#endif
110
111/*struct	termio exp_tty_original;*/
112exp_tty exp_tty_original;
113
114#define GET_TTYTYPE	0
115#define SET_TTYTYPE	1
116static void
117ttytype(request,fd,ttycopy,ttyinit,s)
118int request;
119int fd;
120		/* following are used only if request == SET_TTYTYPE */
121int ttycopy;	/* true/false, copy from /dev/tty */
122int ttyinit;	/* if true, initialize to sane state */
123char *s;	/* stty args, used only if request == SET_TTYTYPE */
124{
125	if (request == GET_TTYTYPE) {
126		if (-1 == ioctl(fd, TCGETA, (char *)&exp_tty_original)) {
127			knew_dev_tty = FALSE;
128			exp_dev_tty = -1;
129		}
130#ifdef TIOCGWINSZ
131		ioctl(fd,TIOCGWINSZ,&winsize);
132#endif
133#if defined(TIOCGSIZE) && !defined(TIOCGWINSZ)
134		ioctl(fd,TIOCGSIZE,&winsize);
135#endif
136	} else {	/* type == SET_TTYTYPE */
137		if (ttycopy && knew_dev_tty) {
138			(void) ioctl(fd, TCSETA, (char *)&exp_tty_current);
139#ifdef TIOCSWINSZ
140			ioctl(fd,TIOCSWINSZ,&winsize);
141#endif
142#if defined(TIOCSSIZE) && !defined(TIOCSWINSZ)
143			ioctl(fd,TIOCGSIZE,&winsize);
144#endif
145		}
146
147		if (ttyinit) {
148			/* overlay parms originally supplied by Makefile */
149			pty_stty(DFLT_STTY,linet);
150		}
151
152		/* lastly, give user chance to override any terminal parms */
153		if (s) {
154			pty_stty(s,linet);
155		}
156	}
157}
158
159void
160exp_init_pty()
161{
162	int npty;
163	char *myline;
164
165	lowpty=0;
166#ifdef _SC_CRAY_NPTY
167	highpty=sysconf(_SC_CRAY_NPTY);
168#else
169	highpty=128;
170#endif /* _SC_CRAY_NPTY */
171
172	ptys = (int *) malloc(sizeof(int)*(highpty+1));
173	if (ptys == NULL) {
174		fprintf(stderr,"exp_init_pty:  couldn't allocate pty array\n");
175		exit(1);
176	}
177	for (npty = lowpty;npty <= highpty;npty++)
178		ptys[npty] = 0;
179
180 	realuid=getuid();	/* get REAL uid */
181 	realgid=getgid();	/* get REAL uid */
182
183	exp_dev_tty = open("/dev/tty",O_RDWR);
184	knew_dev_tty = (exp_dev_tty != -1);
185	if (knew_dev_tty) ttytype(GET_TTYTYPE,exp_dev_tty,0,0,(char *)0);
186
187	/*
188	 * Acquire (as root) current user name and host.
189	 */
190	(void) cuserid(myname);
191	(void) gethostname(hostname,sizeof(hostname));
192
193	/*
194	 * Set the real and effective userids to root using 'setuid'.  Then
195	 * set the real and effective userids to the actual user using
196	 * 'setreuid'.  This allows using 'seteuid' to go back and forth from
197	 * root and the actual userid.  Don't ask me why it works.
198	 */
199	setuid(0);
200	setreuid(realuid,realuid);
201}
202
203/* returns fd of master end of pseudotty */
204int
205exp_getptymaster()
206{
207	struct stat sb;
208	int master;
209	int npty;
210
211	exp_pty_error = 0;
212
213	expDiagLog("exp_getptymaster:  lowpty=%d  highpty=%d\n",lowpty,highpty);
214	for (npty = lowpty; npty <= highpty; npty++) {
215		if (seteuid(0) == -1) {		/* we need to be root! */
216			expDiagLog("exp_getptymaster:  seteuid root errno=%d\n",
217				errno);
218		}
219		(void) sprintf(linep, "/dev/pty/%03d", npty);
220		master = open(linep, O_RDWR);
221
222		if (master < 0) {
223			expDiagLog("exp_getptymaster:  open linep=%s errno=%d\n",
224				linep,errno);
225			continue;
226		}
227
228		(void) sprintf(linet, "/dev/ttyp%03d", npty);
229		if(stat(linet, &sb) < 0) {
230			expDiagLog("exp_getptymaster:  stat linet=%s errno=%d\n",
231				linet,errno);
232			(void) close(master);
233			continue;
234		}
235		if (sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
236                        if (chown(linet, realuid, realgid) == -1) {
237				expDiagLog("exp_getptymaster:  chown linet=%s errno=%d\n",
238					linet,errno);
239			}
240                        if (chmod(linet, 0600) == -1) {
241				expDiagLog("exp_getptymaster:  chmod linet=%s errno=%d\n",
242					linet,errno);
243			}
244                        (void)close(master);
245                        master = open(linep, 2);
246                        if (master < 0) {
247				expDiagLog("exp_getptymaster:  reopen linep=%s errno=%d\n",
248					linep,errno);
249                                continue;
250			}
251                }
252		if (seteuid(realuid) == -1) {	/* back to who we are! */
253			expDiagLog("exp_getptymaster:  seteuid user errno=%d\n",
254				errno);
255		}
256		if (access(linet, R_OK|W_OK) != 0) {
257			expDiagLog("exp_getptymaster:  access linet=%s errno=%d\n",
258				linet,errno);
259			(void) close(master);
260			continue;
261		}
262		expDiagLog("exp_getptymaster:  allocated %s\n",linet);
263		ptys[npty] = -1;
264		exp_pty_slave_name = linet;
265		return(master);
266	}
267	if (seteuid(realuid) == -1) {		/* back to who we are! */
268		expDiagLog("exp_getptymaster:  seteuid user errno=%d\n",errno);
269	}
270	return(-1);
271}
272
273/* see comment in pty_termios.c */
274/*ARGSUSED*/
275void
276exp_slave_control(master,control)
277int master;
278int control;
279{
280}
281
282int
283exp_getptyslave(ttycopy,ttyinit,stty_args)
284int ttycopy;
285int ttyinit;
286char *stty_args;
287{
288	int slave;
289
290	if (0 > (slave = open(linet, O_RDWR))) {
291		expDiagLog("exp_getptyslave:  open linet=%s errno=%d\n",linet,errno);
292		return(-1);
293	}
294
295	/* sanity check - if slave not 0, skip rest of this and return */
296	/* to what will later be detected as an error in caller */
297	if (0 != slave) {
298		expDiagLog("exp_getptyslave:  slave fd not 0\n");
299		 return(slave);
300	}
301
302	if (0 == slave) {
303		/* if opened in a new process, slave will be 0 (and */
304		/* ultimately, 1 and 2 as well) */
305
306		/* duplicate 0 onto 1 and 2 to prepare for stty */
307		fcntl(0,F_DUPFD,1);
308		fcntl(0,F_DUPFD,2);
309	}
310
311	ttytype(SET_TTYTYPE,slave,ttycopy,ttyinit,stty_args);
312	return(slave);
313}
314
315setptyutmp()
316{
317	struct utmp utmp;
318
319	if (seteuid(0) == -1) {		/* Need to be root */
320		expDiagLog("setptyutmp:  setuid root errno=%d\n",errno);
321		return(-1);
322	}
323	(void) time(&utmp.ut_time);
324	utmp.ut_type = USER_PROCESS;
325	utmp.ut_pid = getpid();
326	strncpy(utmp.ut_user,myname,sizeof(utmp.ut_user));
327	strncpy(utmp.ut_host,hostname,sizeof(utmp.ut_host));
328	strncpy(utmp.ut_line,linet+5,sizeof(utmp.ut_line));
329	strncpy(utmp.ut_id,linet+8,sizeof(utmp.ut_id));
330	if (pututline(&utmp) == NULL) {
331		expDiagLog("setptyutmp:  pututline failed\n");
332	}
333	endutent();
334	if (seteuid(realuid) == -1)
335		expDiagLog("setptyutmp:  seteuid user errno=%d\n",errno);
336	return(0);
337}
338
339setptypid(pid)
340int pid;
341{
342        int npty;
343
344        for (npty = lowpty; npty <= highpty; npty++) {
345                if (ptys[npty] < 0) {
346                        expDiagLog("setptypid:  ttyp%03d pid=%d\n",npty,pid);
347                        ptys[npty] = pid;
348                        break;
349                }
350        }
351}
352
353ttyp_reset()
354{
355        int npty;
356
357        if (seteuid(0) == -1) {		/* we need to be root! */
358                expDiagLog("ttyp_reset:  seteuid root errno=%d\n",errno);
359        }
360        for (npty = lowpty; npty <= highpty; npty++) {
361                if (ptys[npty] <= 0)
362                        continue;
363
364                (void) sprintf(linet, "/dev/ttyp%03d", npty);
365                expDiagLog("ttyp_reset:  resetting %s, killing %d\n",
366			linet,ptys[npty]);
367                if (chown(linet,0,0) == -1) {
368                        expDiagLog("ttyp_reset: chown %s errno=%d\n",linet,errno);
369                }
370                if (chmod(linet, 0666) == -1) {
371                        expDiagLog("ttyp_reset: chmod %s errno=%d\n",linet,errno);
372                }
373                resetptyutmp();
374                if (kill(ptys[npty],SIGKILL) == -1) {
375                        expDiagLog("ttyp_reset:  kill pid=%d errno=%d\n",
376                                ptys[npty],errno);
377                }
378        }
379        if (seteuid(realuid) == -1) {   /* Back to who we really are */
380                expDiagLog("ttyp_reset:  seteuid user errno=%d\n",errno);
381        }
382}
383
384void
385exp_pty_exit()
386{
387	ttyp_reset();
388}
389
390resetptyutmp()
391{
392        struct utmp utmp;
393
394        (void) setutent ();
395        /* set up entry to search for */
396        (void) strncpy(utmp.ut_id, linet + strlen(linet) - 4,
397                 sizeof (utmp.ut_id));
398        utmp.ut_type = USER_PROCESS;
399
400        /* position to entry in utmp file */
401        if(getutid(&utmp) == NULL) {
402                expDiagLog("resetptyutmp:  no utmp entry for %s\n",linet);
403                return(-1);     /* no utmp entry for this line ??? */
404        }
405
406        /* set up the new entry */
407        strncpy(utmp.ut_name,"",sizeof(utmp.ut_name));
408        strncpy(utmp.ut_host,"",sizeof(utmp.ut_host));
409        time(&utmp.ut_time);
410        utmp.ut_type = DEAD_PROCESS;
411        utmp.ut_exit.e_exit = 0;
412
413        /* write out the entry */
414        pututline(&utmp);
415
416        /* close the file */
417        (void) endutent();
418        return(0);
419}
420