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