Imported Upstream version 5.45
[platform/upstream/expect.git] / pty_unicos.c
1 /* pty_unicos.c - routines to allocate ptys - for CRAY UNICOS 5.1 and 6.0 */
2
3 /*
4
5 Original by: Don Libes, NIST, 2/6/90
6 Hacked for Unicos 5.1 by: Frank Terhaar-Yonkers, US EPA,  1/10/91
7 Hacked for Unicos 6.0 by: Pete TerMaat, pete@willow.cray.com, 3/27/91
8
9 Design and implementation of this program was paid for by U.S. tax
10 dollars.  Therefore it is public domain.  However, the author and NIST
11 would 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
26 extern 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
59 void 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
70 static char     linep[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
71 static char     linet[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
72 static int      lowpty;
73 static int      highpty;
74 static int      realuid;
75 static int      realgid;
76 static int      *ptys;
77 static char myname[32];
78 static char hostname[MAXHOSTNAMELEN];
79 char *exp_pty_slave_name;
80 char *exp_pty_error;
81
82 static void
83 pty_stty(s,name)
84 char *s;                /* args to stty */
85 char *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
101 int exp_dev_tty;        /* file descriptor to /dev/tty or -1 if none */
102 static int knew_dev_tty;/* true if we had our hands on /dev/tty at any time */
103
104 #ifdef TIOCGWINSZ
105 static struct winsize winsize = {0, 0};
106 #endif
107 #if defined(TIOCGSIZE) && !defined(TIOCGWINSZ)
108 static struct ttysize winsize = {0, 0};
109 #endif
110
111 /*struct        termio exp_tty_original;*/
112 exp_tty exp_tty_original;
113
114 #define GET_TTYTYPE     0
115 #define SET_TTYTYPE     1
116 static void
117 ttytype(request,fd,ttycopy,ttyinit,s)
118 int request;
119 int fd;
120                 /* following are used only if request == SET_TTYTYPE */
121 int ttycopy;    /* true/false, copy from /dev/tty */
122 int ttyinit;    /* if true, initialize to sane state */
123 char *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
159 void
160 exp_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 */
204 int
205 exp_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*/
275 void
276 exp_slave_control(master,control)
277 int master;
278 int control;
279 {
280 }
281
282 int
283 exp_getptyslave(ttycopy,ttyinit,stty_args)
284 int ttycopy;
285 int ttyinit;
286 char *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
315 setptyutmp()
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
339 setptypid(pid)
340 int 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
353 ttyp_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
384 void
385 exp_pty_exit()
386 {
387         ttyp_reset();
388 }
389
390 resetptyutmp()
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 }