home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / k95source / ckupty.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  44KB  |  1,723 lines

  1. /*  C K U P T Y  --  C-Kermit pseudoterminal control functions for UNIX  */
  2.  
  3. /*
  4.   Copyright 1995 by the Massachusetts Institute of Technology.
  5.  
  6.   Permission to use, copy, modify, and distribute this software and its
  7.   documentation for any purpose and without fee is hereby granted, provided
  8.   that the above copyright notice appear in all copies and that both that
  9.   copyright notice and this permission notice appear in supporting
  10.   documentation, and that the name of M.I.T. not be used in advertising or
  11.   publicity pertaining to distribution of the software without specific,
  12.   written prior permission.  Furthermore if you modify this software you must
  13.   label your software as modified software and not distribute it in such a
  14.   fashion that it might be confused with the original M.I.T. software.
  15.   M.I.T. makes no representations about the suitability of this software for
  16.   any purpose.  It is provided "as is" without express or implied warranty.
  17.  
  18.   Modified for use in C-Kermit, and new material added, by:
  19.  
  20.   Jeffrey Altman <jaltman@secure-endpoints.com>
  21.   Secure Endpoints Inc., New York City
  22.   November 1999
  23. */
  24.  
  25. /*
  26.   Built and tested successully on:
  27.    . 4.4BSD, including BSDI/OS, NetBSD, FreeBSD, OpenBSD, Mac OS X
  28.    . AIX 4.1 and later
  29.    . DG/UX 5.4R4.11
  30.    . Digital UNIX 3.2 and 4.0
  31.    . HP-UX 9.00 and later
  32.    . IRIX 6.0 and later
  33.    . Linux
  34.    . NeXTSTEP 3.x
  35.    . QNX 4.25 (except PTY process termination not detected)
  36.    . SCO OSR5.0.5
  37.    . SCO Unixware 7
  38.    . SINIX 5.42
  39.    . Solaris 2.x and 7
  40.    . SunOS 4.1.3
  41.  
  42.   Included but not tested yet in:
  43.    . Macintosh OSX, OpenBSD, and any other BSD44-based system not listed above
  44.  
  45.   Failures include:
  46.    . SCO UNIX 3.2v4.2 (compile fails with syntax error in <memory.h>)
  47.    . HP-UX 8.00 and earlier (no vhangup or ptsname routines)
  48. */
  49.  
  50. #include "ckcsym.h"
  51. #include "ckcdeb.h"            /* To pick up NETPTY definition */
  52.  
  53. #ifndef NETPTY                /* Selector for PTY support */
  54.  
  55. char * ptyver = "No PTY support";
  56.  
  57. #else  /* (rest of this module...) */
  58.  
  59. char * ptyver = "PTY support 8.0.014, 20 Aug 2002";
  60.  
  61. /* These will no doubt need adjustment... */
  62.  
  63. #ifndef NEXT
  64. #define HAVE_SETSID
  65. #endif /* NEXT */
  66. #define HAVE_KILLPG
  67. #define HAVE_TTYNAME
  68. #define HAVE_WAITPID
  69.  
  70. #ifndef USE_TERMIO
  71. #ifdef LINUX
  72. #define USE_TERMIO
  73. #else
  74. #ifdef ATTSV
  75. #define USE_TERMIO
  76. #else
  77. #ifdef HPUX
  78. #define USE_TERMIO
  79. #else
  80. #ifdef AIX
  81. #define USE_TERMIO
  82. #else
  83. #ifdef BSD44ORPOSIX
  84. #define USE_TERMIO
  85. #else
  86. #ifdef IRIX60
  87. #define USE_TERMIO
  88. #else
  89. #ifdef QNX
  90. #define USE_TERMIO
  91. #endif /* QNX */
  92. #endif /* IRIX60 */
  93. #endif /* BSD44ORPOSIX */
  94. #endif /* AIX */
  95. #endif /* HPUX */
  96. #endif /* ATTSV */
  97. #endif /* LINUX */
  98. #endif /* USE_TERMIO */
  99.  
  100. #ifdef QNX
  101. #include <fcntl.h>
  102. #endif /* QNX */
  103.  
  104. #ifdef USE_TERMIO
  105. #define POSIX_TERMIOS            /* Seems to be a misnomer */
  106. #endif /* USE_TERMIO */
  107.  
  108. #ifdef NEXT
  109. #ifndef GETPGRP_ONEARG
  110. #define GETPGRP_ONEARG
  111. #endif /* GETPGRP_ONEARG */
  112. #endif /* NEXT */
  113.  
  114. #ifdef WANT_UTMP            /* See ckupty.h */
  115. /*
  116.   WANT_UTMP is not defined because (a) the utmp/wtmp junk is the most
  117.   nonportable part of this module, and (b) we're not logging anybody
  118.   in, we're just running a process, and don't need to write utmp/wtmp records.
  119. */
  120. #ifndef HAVE_SETUTXENT            /* Who has <utmpx.h> */
  121. #ifdef SOLARIS
  122. #define HAVE_SETUTXENT
  123. #else
  124. #ifdef IRIX60
  125. #define HAVE_SETUTXENT
  126. #else
  127. #ifdef CK_SCOV5
  128. #define HAVE_SETUTXENT
  129. #else
  130. #ifdef HPUX10
  131. #define HAVE_SETUTXENT
  132. #else
  133. #ifdef UNIXWARE
  134. #define HAVE_SETUTXENT
  135. #else
  136. #ifdef IRIX60
  137. #define HAVE_SETUTXENT
  138. #endif /* IRIX60 */
  139. #endif /* UNIXWARE */
  140. #endif /* HPUX10 */
  141. #endif /* CK_SCOV5 */
  142. #endif /* IRIX60 */
  143. #endif /* SOLARIS */
  144. #endif /* HAVE_SETUTXENT */
  145.  
  146. #ifndef HAVE_UTHOST            /* Does utmp include ut_host[]? */
  147. #ifdef HAVE_SETUTXENT            /* utmpx always does */
  148. #define HAVE_UTHOST
  149. #else
  150. #ifdef LINUX                /* Linux does */
  151. #define HAVE_UTHOST
  152. #else
  153. #ifdef SUNOS4                /* SunOS does */
  154. #define HAVE_UTHOST
  155. #else
  156. #ifdef AIX41                /* AIX 4.1 and later do */
  157. #define HAVE_UTHOST
  158. #endif /* AIX41 */
  159. #endif /* SUNOS4 */
  160. #endif /* LINUX */
  161. #endif /* HAVE_SETUTXENT */
  162. #endif /* HAVE_UTHOST */
  163.  
  164. #ifndef HAVE_UT_HOST
  165. #ifndef NO_UT_HOST
  166. #define NO_UT_HOST
  167. #endif /* NO_UT_HOST */
  168. #endif /* HAVE_UT_HOST */
  169.  
  170. #endif /* WANT_UTMP */
  171.  
  172. #ifdef LINUX
  173. #define CK_VHANGUP
  174. #define HAVE_SYS_SELECT_H
  175. #define HAVE_GETUTENT
  176. #define HAVE_SETUTENT
  177. #define HAVE_UPDWTMP
  178. #endif /* LINUX */
  179.  
  180. #ifdef HPUX10
  181. #define CK_VHANGUP
  182. #define VHANG_FIRST
  183. #define HAVE_PTSNAME
  184. #ifndef HAVE_PTYTRAP
  185. #define HAVE_PTYTRAP
  186. #endif /* HAVE_PTYTRAP */
  187. #else
  188. #ifdef HPUX9
  189. #define CK_VHANGUP
  190. #define VHANG_FIRST
  191. #define HAVE_PTSNAME
  192. #ifndef HAVE_PTYTRAP
  193. #define HAVE_PTYTRAP
  194. #endif /* HAVE_PTYTRAP */
  195. #endif /* HPUX9 */
  196. #endif /* HPUX10 */
  197.  
  198. #ifdef SUNOS4
  199. #define CK_VHANGUP
  200. #define NO_UT_PID
  201. #define VHANG_FIRST
  202. #endif /* SUNOS4 */
  203.  
  204. #ifdef IRIX60
  205. #define CK_VHANGUP
  206. #define HAVE__GETPTY
  207. #endif /* IRIX60 */
  208.  
  209. #ifdef SINIX
  210. #define HAVE_STREAMS
  211. #define HAVE_GRANTPT
  212. #define HAVE_PTSNAME
  213. #define PUSH_PTEM
  214. #define PUSH_LDTERM
  215. #define PUSH_TTCOMPAT
  216. #endif /* SINIX */
  217.  
  218. #ifdef ultrix
  219. #define MUST_SETPGRP
  220. #endif /* ultrix */
  221.  
  222. #ifdef QNX
  223. #define MUST_SETPGRP
  224. #define NO_DEVTTY
  225. #define INIT_SPTY
  226. #endif /* QNX */
  227.  
  228. #ifdef LINUX
  229. #ifdef HAVE_PTMX
  230. #define HAVE_GRANTPT
  231. #define HAVE_PTSNAME
  232. #endif /* HAVE_PTMX */
  233. #else
  234. #ifdef HAVE_STREAMS
  235. #define HAVE_PTMX
  236. #endif /* HAVE_STREAMS */
  237. #endif /* LINUX */
  238.  
  239. #include "ckupty.h"
  240.  
  241. #ifdef PTYNOBLOCK
  242. #ifndef O_NDELAY
  243. #ifdef O_NONBLOCK
  244. #define O_NDELAY O_NONBLOCK
  245. #endif /* O_NONBLOCK */
  246. #endif /* O_NDELAY */
  247. #else /* PTYNOBLOCK */
  248. #ifdef O_NDELAY
  249. #undef O_NDELAY
  250. #endif /* O_NDELAY */
  251. #define O_NDELAY 0
  252. #endif /* PTYNOBLOCK */
  253.  
  254. #ifndef ONLCR
  255. #define ONLCR 0
  256. #endif /* ONLCR */
  257.  
  258. #ifdef CK_WAIT_H
  259. #include <sys/wait.h>
  260. #endif /* CK_WAIT_H */
  261.  
  262. #ifdef STREAMSPTY
  263. #ifndef INIT_SPTY
  264. #define INIT_SPTY
  265. #endif /* INIT_SPTY */
  266.  
  267. #include <sys/stream.h>
  268. #include <stropts.h>
  269. #include <termio.h>
  270.  
  271. /* Make sure we don't get the BSD version */
  272.  
  273. #ifdef HAVE_SYS_TTY_H
  274. #include "/usr/include/sys/tty.h"
  275. #endif /* HAVE_SYS_TTY_H */
  276.  
  277. #ifdef HAS_PTYVAR            /* Where is this set? */
  278.  
  279. #include <sys/ptyvar.h>
  280.  
  281. #else /* HAS_PTYVAR */
  282.  
  283. #ifndef TIOCPKT_FLUSHWRITE
  284. #define TIOCPKT_FLUSHWRITE 0x02
  285. #define TIOCPKT_NOSTOP     0x10
  286. #define TIOCPKT_DOSTOP     0x20
  287. #define TIOCPKT_IOCTL      0x40
  288. #endif /* TIOCPKT_FLUSHWRITE */
  289.  
  290. #endif /* HAS_PTYVAR */
  291.  
  292. #ifdef HAVE_TTY_H
  293. #include <tty.h>
  294. #endif /* HAVE_TTY_H */
  295. /*
  296.   Because of the way ptyibuf is used with streams messages, we need
  297.   ptyibuf+1 to be on a full-word boundary.  The following weirdness
  298.   is simply to make that happen.
  299. */
  300. long ptyibufbuf[BUFSIZ/sizeof(long)+1];
  301. char *ptyibuf = ((char *)&ptyibufbuf[1])-1;
  302. char *ptyip = ((char *)&ptyibufbuf[1])-1;
  303. char ptyibuf2[BUFSIZ];
  304. unsigned char ctlbuf[BUFSIZ];
  305. struct strbuf strbufc, strbufd;
  306.  
  307. int readstream();
  308.  
  309. #else  /* ! STREAMSPTY */
  310.  
  311. /* I/O data buffers, pointers, and counters. */
  312.  
  313. char ptyibuf[BUFSIZ], *ptyip = ptyibuf;
  314. char ptyibuf2[BUFSIZ];
  315.  
  316. #endif /* ! STREAMSPTY */
  317.  
  318. #ifndef USE_TERMIO
  319. struct termbuf {
  320.     struct sgttyb sg;
  321.     struct tchars tc;
  322.     struct ltchars ltc;
  323.     int state;
  324.     int lflags;
  325. } termbuf, termbuf2;
  326.  
  327. #define cfsetospeed(tp,val) (tp)->sg.sg_ospeed = (val)
  328. #define cfsetispeed(tp,val) (tp)->sg.sg_ispeed = (val)
  329. #define cfgetospeed(tp)     (tp)->sg.sg_ospeed
  330. #define cfgetispeed(tp)     (tp)->sg.sg_ispeed
  331.  
  332. #else  /* USE_TERMIO */
  333.  
  334. #ifdef SYSV_TERMIO
  335. #define termios termio
  336. #endif /* SYSV_TERMIO */
  337.  
  338. #ifndef TCSANOW
  339.  
  340. #ifdef TCSETS
  341.  
  342. #define TCSANOW TCSETS
  343. #define TCSADRAIN TCSETSW
  344. #define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
  345.  
  346. #else /* TCSETS */
  347.  
  348. #ifdef TCSETA
  349. #define TCSANOW TCSETA
  350. #define TCSADRAIN TCSETAW
  351. #define tcgetattr(f,t) ioctl(f,TCGETA,(char *)t)
  352. #else /* TCSETA */
  353. #define TCSANOW TIOCSETA
  354. #define TCSADRAIN TIOCSETAW
  355. #define tcgetattr(f,t) ioctl(f,TIOCGETA,(char *)t)
  356. #endif /* TCSETA */
  357.  
  358. #endif /* TCSETS */
  359.  
  360. #define tcsetattr(f,a,t) ioctl(f,a,t)
  361. #define cfsetospeed(tp,val) (tp)->c_cflag &= ~CBAUD;(tp)->c_cflag|=(val)
  362. #define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
  363.  
  364. #ifdef CIBAUD
  365. #define cfsetispeed(tp,val) \
  366.  (tp)->c_cflag &= ~CIBAUD; (tp)->c_cflag |= ((val)<<IBSHIFT)
  367. #define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
  368. #else /* CIBAUD */
  369. #define cfsetispeed(tp,val) (tp)->c_cflag &= ~CBAUD; (tp)->c_cflag|=(val)
  370. #define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
  371. #endif /* CIBAUD */
  372.  
  373. #endif /* TCSANOW */
  374.  
  375. struct termios termbuf, termbuf2;       /* pty control structure */
  376.  
  377. #ifdef INIT_SPTY
  378. static int spty = -1;
  379. #endif /* INIT_SPTY */
  380.  
  381. #endif /* USE_TERMIO */
  382.  
  383. extern int ttyfd;                       /* Standard Kermit usage */
  384. static int msg = 0;
  385.  
  386. /* termbuf routines (begin) */
  387. /*
  388.   init_termbuf()
  389.   copy_termbuf(cp)
  390.   set_termbuf()
  391.  
  392.   These three routines are used to get and set the "termbuf" structure
  393.   to and from the kernel.  init_termbuf() gets the current settings.
  394.   copy_termbuf() hands in a new "termbuf" to write to the kernel, and
  395.   set_termbuf() writes the structure into the kernel.
  396. */
  397. VOID
  398. init_termbuf() {
  399.     int rc = 0;
  400.     memset(&termbuf,0,sizeof(termbuf));
  401.     memset(&termbuf2,0,sizeof(termbuf2));
  402. #ifndef    USE_TERMIO
  403.     rc = ioctl(ttyfd, TIOCGETP, (char *)&termbuf.sg);
  404.     rc |= ioctl(ttyfd, TIOCGETC, (char *)&termbuf.tc);
  405.     rc |= ioctl(ttyfd, TIOCGLTC, (char *)&termbuf.ltc);
  406. #ifdef TIOCGSTATE
  407.     rc |= ioctl(ttyfd, TIOCGSTATE, (char *)&termbuf.state);
  408. #endif /* TIOCGSTATE */
  409. #else /* USE_TERMIO */
  410.     errno = 0;
  411. #ifdef INIT_SPTY
  412.     rc = tcgetattr(spty, &termbuf);
  413.     debug(F111,"init_termbuf() tcgetattr(spty)",ckitoa(rc),errno);
  414. #else
  415.     rc = tcgetattr(ttyfd, &termbuf);
  416.     debug(F111,"init_termbuf() tcgetattr(ttyfd)",ckitoa(rc),errno);
  417. #endif /* INIT_SPTY */
  418. #endif /* USE_TERMIO */
  419.     if (!rc)
  420.       termbuf2 = termbuf;
  421. }
  422.  
  423. #ifdef TIOCPKT_IOCTL
  424. VOID
  425. copy_termbuf(cp, len) char *cp; int len; {
  426.     if (len > sizeof(termbuf))
  427.       len = sizeof(termbuf);
  428.     memcpy((char *)&termbuf, cp, len);
  429.     termbuf2 = termbuf;
  430. }
  431. #endif /* TIOCPKT_IOCTL */
  432.  
  433. VOID
  434. set_termbuf() {                /* Only make the necessary changes. */
  435. #ifndef    USE_TERMIO
  436.     if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
  437.       ioctl(ttyfd, TIOCSETN, (char *)&termbuf.sg);
  438.     if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
  439.       ioctl(ttyfd, TIOCSETC, (char *)&termbuf.tc);
  440.     if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
  441.            sizeof(termbuf.ltc)))
  442.       ioctl(ttyfd, TIOCSLTC, (char *)&termbuf.ltc);
  443.     if (termbuf.lflags != termbuf2.lflags)
  444.       ioctl(ttyfd, TIOCLSET, (char *)&termbuf.lflags);
  445. #else  /* USE_TERMIO */
  446.     if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf))) {
  447.     int x;
  448.     errno = 0;
  449. #ifdef INIT_SPTY
  450.     x = tcsetattr(spty, TCSANOW, &termbuf);
  451.     debug(F111,"set_termbuf tcsetattr(spty)",ckitoa(x),errno);
  452. #else
  453.     x = tcsetattr(ttyfd, TCSANOW, &termbuf);
  454.     debug(F111,"set_termbuf tcsetattr(ttyfd)",ckitoa(x),errno);
  455. #endif /* INIT_SPTY */
  456.     }
  457. #endif /* USE_TERMIO */
  458. }
  459. /* termbuf routines (end) */
  460.  
  461. VOID
  462. ptyint_vhangup() {
  463. #ifdef CK_VHANGUP
  464. #ifdef CK_POSIX_SIG
  465.     struct sigaction sa;
  466.     /* Initialize "sa" structure. */
  467.     sigemptyset(&sa.sa_mask);
  468.     sa.sa_flags = 0;
  469.     sa.sa_handler = SIG_IGN;
  470.     sigaction(SIGHUP, &sa, (struct sigaction *)0);
  471.     vhangup();
  472.     sa.sa_handler = SIG_DFL;
  473.     sigaction(SIGHUP, &sa, (struct sigaction *)0);
  474. #else /* CK_POSIX_SIG */
  475.     signal(SIGHUP,SIG_IGN);
  476.     vhangup();
  477.     signal(SIGHUP,SIG_DFL);
  478. #endif /* CK_POSIX_SIG */
  479. #endif /* CK_VHANGUP */
  480. }
  481.  
  482. /*
  483.   This routine is called twice.  It's not particularly important that the
  484.   setsid() or TIOCSTTY ioctls succeed (they may not the second time), but
  485.   rather that we have a controlling terminal at the end.  It is assumed that
  486.   vhangup doesn't exist and confuse the process's notion of controlling
  487.   terminal on any system without TIOCNOTTY.  That is, either vhangup() leaves
  488.   the controlling terminal in tact, breaks the association completely, or the
  489.   system provides TIOCNOTTY to get things back into a reasonable state.  In
  490.   practice, vhangup() either breaks the association completely or doesn't
  491.   effect controlling terminals, so this condition is met.
  492. */
  493. long
  494. ptyint_void_association() {
  495.     int con_fd;
  496. #ifdef HAVE_SETSID
  497.     debug(F110,
  498.       "ptyint_void_association()",
  499.       "setsid()",
  500.       0
  501.       );
  502.     setsid();
  503. #endif /* HAVE_SETSID */
  504.  
  505. #ifndef NO_DEVTTY
  506.     /* Void tty association first */
  507. #ifdef TIOCNOTTY
  508.     con_fd = open("/dev/tty", O_RDWR);
  509.     debug(F111,
  510.       "ptyint_void_association() open(/dev/tty,O_RDWR)",
  511.       "/dev/tty",
  512.       con_fd);
  513.     if (con_fd >= 0) {
  514.         ioctl(con_fd, TIOCNOTTY, 0);
  515.         close(con_fd);
  516.     }
  517. #ifdef DEBUG
  518.     else debug(F101, "ptyint_void_association() open() errno","",errno);
  519. #endif /* DEBUG */
  520. #endif /* TIOCNOTTY */
  521. #endif /* NO_DEVTTY */
  522.     return(0);
  523. }
  524.  
  525. /* PID may be zero for unknown.*/
  526.  
  527. long
  528. pty_cleanup(slave, pid, update_utmp) char *slave; int pid; int update_utmp; {
  529. #ifdef VHANG_LAST
  530.     int retval, fd;
  531. #endif /* VHANG_LAST */
  532.  
  533.     debug(F111,"pty_cleanup()",slave,pid);
  534. #ifdef WANT_UTMP
  535.     if (update_utmp)
  536.       pty_update_utmp(PTY_DEAD_PROCESS,
  537.               0,
  538.               "",
  539.               slave,
  540.               (char *)0,
  541.               PTY_UTMP_USERNAME_VALID
  542.               );
  543. #endif /* WANT_UTMP */
  544.  
  545. #ifdef SETUID
  546.     chmod(slave, 0666);
  547.     chown(slave, 0, 0);
  548. #endif /* SETUID */
  549.  
  550. #ifdef HAVE_REVOKE
  551.     revoke(slave);
  552.     /*
  553.        Revoke isn't guaranteed to send a SIGHUP to the processes it
  554.        dissociates from the terminal.  The best solution without a Posix
  555.        mechanism for forcing a hangup is to killpg() the process group of the
  556.        pty.  This will at least kill the shell and hopefully, the child
  557.        processes.  This is not always the case, however.  If the shell puts
  558.        each job in a process group and doesn't pass along SIGHUP, all
  559.        processes may not die.
  560.     */
  561.     if (pid > 0) {
  562. #ifdef HAVE_KILLPG
  563.     killpg(pid, SIGHUP);
  564. #else
  565.     kill(-(pid), SIGHUP);
  566. #endif /*HAVE_KILLPG*/
  567.     }
  568. #else /* HAVE_REVOKE*/
  569. #ifdef VHANG_LAST
  570.     {
  571.         int status;
  572. #ifdef CK_POSIX_SIG
  573.         sigset_t old, new;
  574.         sigemptyset(&new);
  575.         sigaddset(&new, SIGCHLD);
  576.         sigprocmask(SIG_BLOCK, &new, &old);
  577. #else /*CK_POSIX_SIG*/
  578.         int mask = sigblock(sigmask(SIGCHLD));
  579. #endif /*CK_POSIX_SIG*/
  580.         switch (retval = fork()) {
  581.       case -1:
  582. #ifdef CK_POSIX_SIG
  583.             sigprocmask(SIG_SETMASK, &old, 0);
  584. #else /*CK_POSIX_SIG*/
  585.             sigsetmask(mask);
  586. #endif /*CK_POSIX_SIG*/
  587.             return errno;
  588.       case 0:
  589.             ptyint_void_association();
  590.             if (retval = (pty_open_ctty(slave, &fd)))
  591.           exit(retval);
  592.             ptyint_vhangup();
  593.             exit(0);
  594.         break;
  595.       default:
  596. #ifdef HAVE_WAITPID
  597.             waitpid(retval, &status, 0);
  598. #else /*HAVE_WAITPID*/
  599.             wait(&status);
  600. #endif /* HAVE_WAITPID */
  601. #ifdef CK_POSIX_SIG
  602.             sigprocmask(SIG_SETMASK, &old, 0);
  603. #else /*CK_POSIX_SIG*/
  604.             sigsetmask(mask);
  605. #endif /*CK_POSIX_SIG*/
  606.             break;
  607.         }
  608.     }
  609. #endif /*VHANG_LAST*/
  610. #endif /* HAVE_REVOKE*/
  611. #ifndef HAVE_STREAMS
  612.     slave[strlen("/dev/")] = 'p';
  613. #ifdef SETUID
  614.     chmod(slave, 0666);
  615.     chown(slave, 0, 0);
  616. #endif /* SETUID */
  617. #endif /* HAVE_STREAMS */
  618.     return(0);
  619. }
  620.  
  621. long
  622. pty_getpty(fd, slave, slavelength) int slavelength; int *fd; char *slave; {
  623.     char *cp;
  624.     char *p;
  625.     int i, ptynum;
  626.     struct stat stb;
  627. #ifndef HAVE_OPENPTY
  628. #ifndef HAVE__GETPTY
  629.     char slavebuf[1024];
  630. #endif /* HAVE__GETPTY */
  631. #endif /* HAVE_OPENPTY */
  632. #ifdef HAVE__GETPTY
  633.     char *slaveret;            /* Temp to hold pointer to slave */
  634. #endif /*HAVE__GETPTY*/
  635.  
  636. #ifdef HAVE_OPENPTY
  637.     int slavefd;
  638.  
  639.     debug(F100,"HAVE_OPENPTY","",0);
  640.     if (openpty(fd,
  641.         &slavefd,
  642.         slave,
  643.         (struct termios *)0,
  644.         (struct winsize *)0
  645.         )
  646.     )
  647.       return(1);
  648.     close(slavefd);
  649.     return(0);
  650.  
  651. #else /* HAVE_OPENPTY */
  652.  
  653. #ifdef HAVE__GETPTY
  654. /*
  655.   This code is included for Irix; as of version 5.3, Irix has /dev/ptmx, but
  656.   it fails to work properly; even after calling unlockpt, root gets permission
  657.   denied opening the pty.  The code to support _getpty should be removed if
  658.   Irix gets working streams ptys in favor of maintaining the least needed code
  659.   paths.
  660. */
  661.     debug(F100,"HAVE__GETPTY","",0);
  662.     if ((slaveret = _getpty(fd, O_RDWR | O_NDELAY, 0600, 0)) == 0) {
  663.     *fd = -1;
  664.     return(PTY_GETPTY_NOPTY);
  665.     }
  666.     if (strlen(slaveret) > slavelength - 1) {
  667.     close(*fd);
  668.     *fd = -1;
  669.     return(PTY_GETPTY_SLAVE_TOOLONG);
  670.     } else {
  671.     ckstrncpy(slave, slaveret, slavelength);
  672.     }
  673.     return(0);
  674.  
  675. #else /* HAVE__GETPTY */
  676.  
  677.     *fd = open("/dev/ptym/clone", O_RDWR|O_NDELAY); /* HPUX */
  678.     if (*fd >= 0) {
  679.         debug(F110,"pty_getpty()","open(/dev/ptym/clone) success",0);
  680.         goto have_fd;
  681.     }
  682.  
  683. #ifdef HAVE_PTMX
  684.     debug(F100,"HAVE_PTMX","",0);
  685.     *fd = open("/dev/ptmx",O_RDWR|O_NDELAY);
  686.     if (*fd >= 0) {
  687.         debug(F110,"pty_getpty()","open(/dev/ptmx) success",0);
  688.         goto have_fd;
  689.     }
  690. #endif /* HAVE_PTMX */
  691.  
  692.     *fd = open("/dev/ptc", O_RDWR|O_NDELAY); /* AIX */
  693.     if (*fd >= 0) {
  694.         debug(F110,"pty_getpty()","open(/dev/ptc) success",0);
  695.         goto have_fd;
  696.     }
  697.     *fd = open("/dev/pty", O_RDWR|O_NDELAY); /* sysvimp */
  698.     if (*fd >= 0)
  699.         debug(F110,"pty_getpty()","open(/dev/pty) success",0);
  700.  
  701.   have_fd:
  702.     if (*fd >= 0) {
  703. #ifdef HAVE_GRANTPT
  704. #ifdef HAVE_PTMX
  705.         debug(F100,"HAVE_GRANTPT","",0);
  706.     if (grantpt(*fd) || unlockpt(*fd))
  707.       return(PTY_GETPTY_STREAMS);
  708. #endif /* HAVE_PTMX */
  709. #endif /* HAVE_GRANTPT */
  710.  
  711. #ifdef HAVE_PTSNAME
  712.         debug(F100,"HAVE_PTSNAME","",0);
  713.     p = (char *)ptsname(*fd);
  714.         debug(F110,"pty_getpty() ptsname()",p,0);
  715. #else
  716. #ifdef HAVE_TTYNAME
  717.         debug(F100,"HAVE_TTYNAME","",0);
  718.     p = ttyname(*fd);
  719.         debug(F110,"pty_getpty() ttyname()",p,0);
  720. #else
  721.     /* XXX If we don't have either what do we do? */
  722.       return(PTY_GETPTY_NOPTY);    /* punt */
  723. #endif /* HAVE_TTYNAME */
  724. #endif /* HAVE_PTSNAME */
  725.     if (p) {
  726.         if (strlen(p) > slavelength - 1) {
  727.                 close (*fd);
  728.                 *fd = -1;
  729.                 return(PTY_GETPTY_SLAVE_TOOLONG);
  730.         }
  731.         ckstrncpy(slave, p, slavelength);
  732.         return(0);
  733.     }
  734.     if (fstat(*fd, &stb) < 0) {
  735.         close(*fd);
  736.         return(PTY_GETPTY_FSTAT);
  737.     }
  738.     ptynum = (int)(stb.st_rdev&0xFF);
  739.     sprintf(slavebuf, "/dev/ttyp%x", ptynum); /* safe */
  740.     if (strlen(slavebuf) > slavelength - 1) {
  741.         close(*fd);
  742.         *fd = -1;
  743.         return(PTY_GETPTY_SLAVE_TOOLONG);
  744.     }
  745.         debug(F110,"pty_getpty() slavebuf",slavebuf,0);
  746.     ckstrncpy(slave, slavebuf, slavelength);
  747.     return(0);
  748.     } else {
  749.         for (cp = "pqrstuvwxyzPQRST";*cp; cp++) {
  750.         sprintf(slavebuf,"/dev/ptyXX"); /* safe */
  751.         slavebuf[sizeof("/dev/pty") - 1] = *cp;
  752.         slavebuf[sizeof("/dev/ptyp") - 1] = '0';
  753.         if (stat(slavebuf, &stb) < 0)
  754.           break;
  755.         for (i = 0; i < 16; i++) {
  756.         slavebuf[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
  757.         *fd = open(slavebuf, O_RDWR|O_NDELAY);
  758.         if (*fd < 0)
  759.           continue;
  760.                 debug(F110,"pty_getpty() found pty master",slavebuf,0);
  761.         slavebuf[sizeof("/dev/") - 1] = 't'; /* got pty */
  762.         if (strlen(slavebuf) > slavelength -1) {
  763.             close(*fd);
  764.             *fd = -1;
  765.             return(PTY_GETPTY_SLAVE_TOOLONG);
  766.         }
  767.                 debug(F110,"pty_getpty() slavebuf [2]",slavebuf,0);
  768.         ckstrncpy(slave, slavebuf, slavelength);
  769.         return(0);
  770.         }
  771.     }
  772.     return(PTY_GETPTY_NOPTY);
  773.     }
  774. #endif /*HAVE__GETPTY*/
  775. #endif /* HAVE_OPENPTY */
  776. }
  777.  
  778. long
  779. pty_init() {
  780. #ifdef HAVE_PTYM
  781.     static char dummy;
  782.     debug(F100,"HAVE_PTYM","",0);
  783.     tty_bank =  &master_name[strlen("/dev/ptym/pty")];
  784.     tty_num  =  &master_name[strlen("/dev/ptym/ptyX")];
  785.     slave_bank = &slave_name[strlen("/dev/pty/tty")];
  786.     slave_num  = &slave_name[strlen("/dev/pty/ttyX")];
  787. #endif
  788.     return(0L);
  789. }
  790.  
  791. /*
  792.   The following is an array of modules that should be pushed on the stream.
  793.   See configure.in for caviats and notes about when this array is used and not
  794.   used.
  795. */
  796. #ifdef HAVE_STREAMS
  797. #ifndef HAVE_LINE_PUSH
  798. static char *push_list[] = {
  799. #ifdef PUSH_PTEM
  800.     "ptem",
  801. #endif
  802. #ifdef PUSH_LDTERM
  803.     "ldterm",
  804. #endif
  805. #ifdef PUSH_TTCOMPAT
  806.     "ttcompat",
  807. #endif
  808.     0
  809. };
  810. #endif /* HAVE_LINE_PUSH */
  811. #endif /* HAVE_STREAMS */
  812.  
  813. long
  814. pty_initialize_slave (fd) int fd; {
  815. #ifdef POSIX_TERMIOS
  816. #ifndef ultrix
  817.     struct termios new_termio;
  818. #else
  819.     struct sgttyb b;
  820. #endif /* ultrix */
  821. #else
  822.     struct sgttyb b;
  823. #endif /* POSIX_TERMIOS */
  824.     int pid;
  825. #ifdef POSIX_TERMIOS
  826. #ifndef ultrix
  827.     int rc;
  828. #endif /* ultrix */
  829. #endif /* POSIX_TERMIOS */
  830.  
  831.     debug(F111,"pty_initialize_slave()","fd",fd);
  832.  
  833. #ifdef HAVE_STREAMS
  834. #ifdef HAVE_LINE_PUSH
  835.     while (ioctl(fd,I_POP,0) == 0) ;    /* Clear out any old lined's */
  836.  
  837.     if (line_push(fd) < 0) {
  838.         debug(F110,"pty_initialize_slave()","line_push() failed",0);
  839.     close(fd);
  840.         fd = -1;
  841.         return(PTY_OPEN_SLAVE_LINE_PUSHFAIL);
  842.     }
  843. #else /*No line_push */
  844.     {
  845.         char **module = &push_list[0];
  846.         while (*module) {
  847.         if (ioctl(fd, I_PUSH, *(module++)) < 0) {
  848.                 debug(F110,"pty_initialize_slave()","ioctl(I_PUSH) failed",0);
  849.         return(PTY_OPEN_SLAVE_PUSH_FAIL);
  850.         }
  851.     }
  852.     }
  853. #endif /*LINE_PUSH*/
  854. #endif /*HAVE_STREAMS*/
  855. /*
  856.   Under Ultrix 3.0, the pgrp of the slave pty terminal needs to be set
  857.   explicitly.  Why rlogind works at all without this on 4.3BSD is a mystery.
  858. */
  859. #ifdef GETPGRP_ONEARG
  860.     pid = getpgrp(getpid());
  861. #else
  862.     pid = getpgrp();
  863. #endif /* GETPGRP_ONEARG */
  864.  
  865.     debug(F111,"pty_initialize_slave()","pid",pid);
  866.  
  867. #ifdef TIOCSPGRP
  868.     ioctl(fd, TIOCSPGRP, &pid);
  869. #endif /* TIOCSPGRP */
  870.  
  871. #ifdef POSIX_TERMIOS
  872. #ifndef ultrix
  873.     tcsetpgrp(fd, pid);
  874.     errno = 0;
  875.     rc = tcgetattr(fd,&new_termio);
  876.     debug(F111,"pty_initialize_slave tcgetattr(fd)",ckitoa(rc),errno);
  877.     if (rc == 0) {
  878.     new_termio.c_cc[VMIN] = 1;
  879.     new_termio.c_cc[VTIME] = 0;
  880.     rc = tcsetattr(fd,TCSANOW,&new_termio);
  881.     debug(F111,"pty_initialize_slave tcsetattr(fd)",ckitoa(rc),errno);
  882.     }
  883. #endif /* ultrix */
  884. #endif /* POSIX_TERMIOS */
  885.     return(0L);
  886. }
  887.  
  888. #ifdef WANT_UTMP
  889. long
  890. pty_logwtmp (tty, user, host) char *user, *tty, *host; {
  891. #ifdef HAVE_LOGWTMP
  892.     logwtmp(tty,user,host);
  893.     return(0);
  894. #else
  895.     struct utmp ut;
  896.     char *tmpx;
  897.     char utmp_id[5];
  898.     int loggingin = user[0];        /* Will be empty for logout */
  899.  
  900. #ifndef NO_UT_HOST
  901.     strncpy(ut.ut_host, host, sizeof(ut.ut_host));
  902. #endif /* NO_UT_HOST */
  903.  
  904.     strncpy(ut.ut_line, tty, sizeof(ut.ut_line));
  905.     ut.ut_time = time(0);
  906.  
  907. #ifndef NO_UT_PID
  908.     ut.ut_pid = getpid();
  909.     strncpy(ut.ut_user, user, sizeof(ut.ut_user));
  910.  
  911.     tmpx = tty + strlen(tty) - 2;
  912.     ckmakmsg(utmp_id,5,"kr",tmpx,NULL,NULL);
  913.     strncpy(ut.ut_id, utmp_id, sizeof(ut.ut_id));
  914.     ut.ut_pid = (loggingin ? getpid() : 0);
  915.     ut.ut_type = (loggingin ? USER_PROCESS : DEAD_PROCESS);
  916. #else
  917.     strncpy(ut.ut_name, user, sizeof(ut.ut_name));
  918. #endif /* NO_UT_PID */
  919.  
  920.     return(ptyint_update_wtmp(&ut, host, user));
  921.  
  922. #endif /* HAVE_LOGWTMP */
  923. }
  924. #endif /* WANT_UTMP */
  925.  
  926. /*
  927.   This routine is called twice.  It's not particularly important that the
  928.   setsid() or TIOCSTTY ioctls succeed (they may not the second time), but
  929.   rather that we have a controlling terminal at the end.  It is assumed that
  930.   vhangup doesn't exist and confuse the process's notion of controlling
  931.   terminal on any system without TIOCNOTTY.  That is, either vhangup() leaves
  932.   the controlling terminal in tact, breaks the association completely, or the
  933.   system provides TIOCNOTTY to get things back into a reasonable state.  In
  934.   practice, vhangup() either breaks the association completely or doesn't
  935.   effect controlling terminals, so this condition is met.
  936. */
  937. long
  938. pty_open_ctty(slave, fd) char * slave; int *fd; {
  939.     int retval;
  940.  
  941.     debug(F110,"pty_open_ctty() slave",slave,0);
  942.  
  943. /* First, dissociate from previous terminal */
  944.  
  945.     if ((retval = ptyint_void_association()) != 0) {
  946.         debug(F111,
  947.           "pty_open_ctty()",
  948.           "ptyint_void_association() failed",
  949.           retval
  950.           );
  951.     return(retval);
  952.     }
  953.  
  954. #ifdef MUST_SETPGRP
  955. /*
  956.   The Ultrix (and other BSD tty drivers) require the process group
  957.   to be zero in order to acquire the new tty as a controlling tty.
  958. */
  959.     setpgrp(0,0);
  960. #endif /* MUST_SETPGRP */
  961.  
  962.     errno = 0;
  963.     *fd = open(slave, O_RDWR);
  964.     if (*fd < 0) {
  965.     debug(F111,"pty_open_ctty() open failure", slave, errno);
  966.     return(PTY_OPEN_SLAVE_OPENFAIL);
  967.     }
  968. #ifdef DEBUG
  969.     else if (deblog) {
  970.     debug(F110, "pty_open_ctty() open ok", slave, 0);
  971.     }
  972. #endif /* DEBUG */
  973.  
  974. #ifdef MUST_SETPGRP
  975.     setpgrp(0, getpid());
  976. #endif /* MUST_SETPGRP */
  977.  
  978. #ifdef TIOCSCTTY
  979.     errno = 0;
  980.     retval = ioctl(*fd, TIOCSCTTY, 0); /* Don't check return.*/
  981.     debug(F111,"pty_open_ctty() ioctl TIOCSCTTY",ckitoa(retval),errno);
  982. #endif /* TIOCSTTY */
  983.     return(0L);
  984. }
  985.  
  986. long
  987. pty_open_slave(slave, fd) char *slave; int *fd; {
  988.     int vfd, testfd;
  989.     long retval;
  990. #ifdef CK_POSIX_SIG
  991.     struct sigaction sa;
  992.  
  993.     sigemptyset(&sa.sa_mask);        /* Initialize "sa" structure. */
  994.     sa.sa_flags = 0;
  995. #endif /* CK_POSIX_SIG */
  996.  
  997. /*
  998.   First, chmod and chown the slave.  If we have vhangup then we really need
  999.   pty_open_ctty to make sure our controlling terminal is the pty we're
  1000.   opening.  However, if we are using revoke or nothing then we just need a
  1001.   file descriiptor for the pty.  Considering some OSes in this category break
  1002.   on the second call to open_ctty (currently OSF but others may), we simply
  1003.   use a descriptor if we can.
  1004. */
  1005. #ifdef VHANG_FIRST
  1006.     if ((retval = pty_open_ctty(slave, &vfd)) != 0) {
  1007.         debug(F111,
  1008.           "pty_open_slave() VHANG_FIRST",
  1009.           "pty_open_ctty() failed",
  1010.           retval
  1011.           );
  1012.         return(retval);
  1013.     }
  1014.     if (vfd < 0) {
  1015.         debug(F111,
  1016.           "pty_open_slave() VHANG_FIRST",
  1017.           "PTY_OPEN_SLAVE_OPENFAIL",
  1018.           vfd
  1019.           );
  1020.     return(PTY_OPEN_SLAVE_OPENFAIL);
  1021.     }
  1022. #endif /* VHANG_FIRST */
  1023.  
  1024.     if (slave == NULL || *slave == '\0') {
  1025.         debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_TOOSHORT",0);
  1026.         return(PTY_OPEN_SLAVE_TOOSHORT);
  1027.     }
  1028.  
  1029. #ifdef SETUID
  1030.     if (chmod(slave, 0)) {
  1031.         debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_CHMODFAIL",0);
  1032.         return(PTY_OPEN_SLAVE_CHMODFAIL);
  1033.     }
  1034.     if (chown(slave, 0, 0 ) == -1 ) {
  1035.         debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_CHOWNFAIL",0);
  1036.         return(PTY_OPEN_SLAVE_CHOWNFAIL);
  1037.     }
  1038. #endif /* SETUID */
  1039. #ifdef VHANG_FIRST
  1040.     ptyint_vhangup();
  1041.     close(vfd);
  1042. #endif /* VHANG_FIRST */
  1043.  
  1044.     if ((retval = ptyint_void_association()) != 0) {
  1045.         debug(F111,
  1046.           "pty_open_slave()",
  1047.           "ptyint_void_association() failed",
  1048.           retval
  1049.           );
  1050.         return(retval);
  1051.     }
  1052.  
  1053. #ifdef HAVE_REVOKE
  1054.     if (revoke (slave) < 0 ) {
  1055.         debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_REVOKEFAIL",0);
  1056.     return(PTY_OPEN_SLAVE_REVOKEFAIL);
  1057.     }
  1058. #endif /* HAVE_REVOKE */
  1059.  
  1060. /* Open the pty for real. */
  1061.  
  1062.     retval = pty_open_ctty(slave, fd);
  1063.     if (retval != 0) {
  1064.         debug(F111,"pty_open_slave()","pty_open_ctty() failed",retval);
  1065.     return(PTY_OPEN_SLAVE_OPENFAIL);
  1066.     }
  1067.     retval = pty_initialize_slave(*fd);
  1068.     if (retval) {
  1069.         debug(F111,"pty_open_slave()","pty_initialize_slave() failed",retval);
  1070.         return(retval);
  1071.     }
  1072. #ifndef NO_DEVTTY
  1073.     errno = 0;
  1074.     testfd = open("/dev/tty", O_RDWR|O_NDELAY);
  1075.     if (testfd < 0) {
  1076.         debug(F111,"pty_open_slave() open failed","/dev/tty",errno);
  1077.     close(*fd);
  1078.     *fd = -1;
  1079.     return(PTY_OPEN_SLAVE_NOCTTY);
  1080.     }
  1081.     close(testfd);
  1082. #endif /* NO_DEVTTY */
  1083.     debug(F110,"pty_open_slave()","success",0);
  1084.     return(0L);
  1085. }
  1086.  
  1087. #ifdef WANT_UTMP
  1088.  
  1089. #ifndef UTMP_FILE
  1090. #ifdef _PATH_UTMP
  1091. #define UTMP_FILE _PATH_UTMP
  1092. #endif /* _PATH_UTMP */
  1093. #endif /*  UTMP_FILE */
  1094.  
  1095. /* If it is *still* missing, assume /etc/utmp */
  1096.  
  1097. #ifndef UTMP_FILE
  1098. #define    UTMP_FILE "/etc/utmp"
  1099. #endif /* UTMP_FILE */
  1100.  
  1101. #ifndef NO_UT_PID
  1102. #define WTMP_REQUIRES_USERNAME
  1103. #endif /* NO_UT_PID */
  1104.  
  1105. long
  1106. pty_update_utmp(process_type, pid, username, line, host, flags)
  1107.     int process_type;
  1108.     int pid;
  1109.     char *username, *line, *host;
  1110.     int flags;
  1111. /* pty_update_utmp */ {
  1112.     struct utmp ent, ut;
  1113. #ifndef HAVE_SETUTENT
  1114.     struct stat statb;
  1115.     int tty;
  1116. #endif /* HAVE_SETUTENT */
  1117. #ifdef HAVE_SETUTXENT
  1118.     struct utmpx utx;
  1119. #endif /* HAVE_SETUTXENT */
  1120. #ifndef NO_UT_PID
  1121.     char *tmpx;
  1122.     char utmp_id[5];
  1123. #endif /* NO_UT_PID */
  1124.     char userbuf[32];
  1125.     int fd;
  1126.  
  1127.     debug(F100,"pty_update_utmp()","",0);
  1128.     strncpy(ent.ut_line, line+sizeof("/dev/")-1, sizeof(ent.ut_line));
  1129.     ent.ut_time = time(0);
  1130.  
  1131. #ifdef NO_UT_PID
  1132.     if (process_type == PTY_LOGIN_PROCESS)
  1133.       return(0L);
  1134. #else /* NO_UT_PID */
  1135.  
  1136.     ent.ut_pid = pid;
  1137.  
  1138.     switch (process_type) {
  1139.       case PTY_LOGIN_PROCESS:
  1140.     ent.ut_type = LOGIN_PROCESS;
  1141.     break;
  1142.       case PTY_USER_PROCESS:
  1143.     ent.ut_type = USER_PROCESS;
  1144.     break;
  1145.       case PTY_DEAD_PROCESS:
  1146.     ent.ut_type = DEAD_PROCESS;
  1147.     break;
  1148.       default:
  1149.     return(PTY_UPDATE_UTMP_PROCTYPE_INVALID);
  1150.     }
  1151. #endif /*NO_UT_PID*/
  1152.  
  1153. #ifndef NO_UT_HOST
  1154.     if (host)
  1155.       strncpy(ent.ut_host, host, sizeof(ent.ut_host));
  1156.     else
  1157.       ent.ut_host[0] = '\0';
  1158. #endif /* NO_UT_HOST */
  1159.  
  1160. #ifndef NO_UT_PID
  1161.     if (!strcmp (line, "/dev/console")) {
  1162.     char * s = NULL;
  1163.  
  1164. #ifdef sun
  1165. #ifdef __SVR4
  1166.     s = "co";
  1167. #else
  1168.     s = "cons";
  1169. #endif /* __SVR4 */
  1170. #else
  1171.     s = "cons";
  1172. #endif /* sun */
  1173.  
  1174.     strncpy(ent.ut_id, s, 4);
  1175.  
  1176.     } else {
  1177.  
  1178.     tmpx = line + strlen(line)-1;
  1179.     if (*(tmpx-1) != '/') tmpx--;    /* last 2 chars unless it's a '/' */
  1180. #ifdef __hpux
  1181.     ckstrncpy(utmp_id, tmpx, 5);
  1182. #else
  1183.     ckmakmsg(utmp_id,5,"kl",tmpx,NULL,NULL);
  1184. #endif /* __hpux */
  1185.     strncpy(ent.ut_id, utmp_id, sizeof(ent.ut_id));
  1186.     }
  1187.     strncpy(ent.ut_user, username, sizeof(ent.ut_user));
  1188.  
  1189. #else
  1190.  
  1191.     strncpy(ent.ut_name, username, sizeof(ent.ut_name));
  1192.  
  1193. #endif /* NO_UT_PID */
  1194.  
  1195.     if (username[0])
  1196.       strncpy(userbuf, username, sizeof(userbuf));
  1197.     else
  1198.       userbuf[0] = '\0';
  1199.  
  1200. #ifdef HAVE_SETUTENT
  1201.  
  1202.     utmpname(UTMP_FILE);
  1203.     setutent();
  1204. /*
  1205.   If we need to preserve the user name in the wtmp structure and Our flags
  1206.   tell us we can obtain it from the utmp and we succeed in obtaining it, we
  1207.   then save the utmp structure we obtain, write out the utmp structure and
  1208.   change the username pointer so it is used by update_wtmp.
  1209. */
  1210.  
  1211. #ifdef WTMP_REQUIRES_USERNAME
  1212.     if ((!username[0]) && (flags&PTY_UTMP_USERNAME_VALID) &&line) {
  1213.     struct utmp *utptr;
  1214.     strncpy(ut.ut_line, line, sizeof(ut.ut_line));
  1215.     utptr = getutline(&ut);
  1216.     if (utptr)
  1217.       strncpy(userbuf,utptr->ut_user,sizeof(ut.ut_user));
  1218.     }
  1219. #endif /* WTMP_REQUIRES_USERNAME */
  1220.  
  1221.     pututline(&ent);
  1222.     endutent();
  1223.  
  1224. #ifdef HAVE_SETUTXENT
  1225.     setutxent();
  1226. #ifdef HAVE_GETUTMPX
  1227.     getutmpx(&ent, &utx);
  1228. #else /* HAVE_GETUTMPX */
  1229.     /* For platforms like HPUX and Dec Unix which don't have getutmpx */
  1230.     strncpy(utx.ut_user, ent.ut_user, sizeof(ent.ut_user));
  1231.     strncpy(utx.ut_id, ent.ut_id, sizeof(ent.ut_id));
  1232.     strncpy(utx.ut_line, ent.ut_line, sizeof(ent.ut_line));
  1233.     utx.ut_pid = pid;        /* kludge for Irix, etc. to avoid trunc. */
  1234.     utx.ut_type = ent.ut_type;
  1235. #ifdef UT_EXIT_STRUCTURE_DIFFER
  1236.     utx.ut_exit.ut_exit = ent.ut_exit.e_exit;
  1237. #else /* UT_EXIT_STRUCTURE_DIFFER */
  1238. /* KLUDGE for now; eventually this will be a feature test... See PR#[40] */
  1239. #ifdef __hpux
  1240.     utx.ut_exit.__e_termination = ent.ut_exit.e_termination;
  1241.     utx.ut_exit.__e_exit = ent.ut_exit.e_exit;
  1242. #else /* __hpux */
  1243.     /* XXX do nothing for now; we don't even know the struct member exists */
  1244. #endif /* __hpux */
  1245. #endif /* UT_EXIT_STRUCTURE_DIFFER */
  1246.     utx.ut_tv.tv_sec = ent.ut_time;
  1247.     utx.ut_tv.tv_usec = 0;
  1248. #endif /* HAVE_GETUTMPX */
  1249.     if (host)
  1250.       strncpy(utx.ut_host, host, sizeof(utx.ut_host));
  1251.     else
  1252.       utx.ut_host[0] = 0;
  1253.     pututxline(&utx);
  1254.     endutxent();
  1255. #endif /* HAVE_SETUTXENT */
  1256.  
  1257. #else /* HAVE_SETUTENT */
  1258.     if (flags&PTY_TTYSLOT_USABLE) {
  1259.     tty = ttyslot();
  1260.     } else {
  1261.     int lc;
  1262.     tty = -1;
  1263.     if ((fd = open(UTMP_FILE, O_RDWR)) < 0)
  1264.       return(errno);
  1265.     for (lc = 0;
  1266.          lseek(fd, (off_t)(lc * sizeof(struct utmp)), SEEK_SET) != -1;
  1267.          lc++
  1268.          ) {
  1269.         if (read(fd,
  1270.              (char *)&ut,
  1271.              sizeof(struct utmp)
  1272.              ) != sizeof(struct utmp)
  1273.         )
  1274.           break;
  1275.         if (strncmp(ut.ut_line, ent.ut_line, sizeof(ut.ut_line)) == 0) {
  1276.         tty = lc;
  1277. #ifdef WTMP_REQUIRES_USERNAME
  1278.         if (!username&&(flags&PTY_UTMP_USERNAME_VALID))
  1279.           strncpy(userbuf, ut.ut_user, sizeof(ut.ut_user));
  1280. #endif /* WTMP_REQUIRES_USERNAME */
  1281.         break;
  1282.         }
  1283.     }
  1284.     close(fd);
  1285.     }
  1286.     if (tty > 0 && (fd = open(UTMP_FILE, O_WRONLY, 0)) >= 0) {
  1287.     lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
  1288.     write(fd, (char *)&ent, sizeof(struct utmp));
  1289.     close(fd);
  1290.     }
  1291. #endif /* HAVE_SETUTENT */
  1292.  
  1293.     /* Don't record LOGIN_PROCESS entries. */
  1294.     if (process_type == PTY_LOGIN_PROCESS)
  1295.       return(0);
  1296.     else
  1297.       return(ptyint_update_wtmp(&ent, host, userbuf));
  1298. }
  1299. #ifndef WTMP_FILE
  1300. #ifdef _PATH_WTMP
  1301. #define WTMP_FILE _PATH_WTMP
  1302. #endif /* _PATH_WTMP */
  1303. #endif /* WTMP_FILE */
  1304.  
  1305. #ifndef WTMPX_FILE
  1306. #ifdef _PATH_WTMPX
  1307. #ifdef HAVE_UPDWTMPX
  1308. #define WTMPX_FILE _PATH_WTMPX
  1309. #endif /* HAVE_UPDWTMPX */
  1310. #endif /* _PATH_WTMPX */
  1311. #endif /* WTMPX_FILE */
  1312.  
  1313. /* If it is *still* missing, assume /usr/adm/wtmp */
  1314.  
  1315. #ifndef WTMP_FILE
  1316. #define    WTMP_FILE "/usr/adm/wtmp"
  1317. #endif /* WTMP_FILE */
  1318.  
  1319. #ifdef COMMENT
  1320. /* The following test can not be made portably */
  1321.  
  1322. /* #if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) */
  1323. /*
  1324.   This is ugly, but the lack of standardization in the utmp/utmpx space, and
  1325.   what glibc implements and doesn't make available, is even worse.
  1326. */
  1327. /* #undef HAVE_UPDWTMPX */    /* Don't use updwtmpx for glibc 2.1 */
  1328. /* #endif */ /* __GLIBC__ etc */
  1329.  
  1330. #else  /* COMMENT */
  1331.  
  1332. #ifdef __GLIBC__
  1333. #undef HAVE_UPDWTMPX        /* Don't use updwtmpx for glibc period */
  1334. #endif /* __GLIBC__ */
  1335. #endif /* COMMENT */
  1336.  
  1337. long
  1338. ptyint_update_wtmp(ent,host,user) struct utmp *ent; char *host; char *user; {
  1339.     struct utmp ut;
  1340.     struct stat statb;
  1341.     int fd;
  1342.     time_t uttime;
  1343. #ifdef HAVE_UPDWTMPX
  1344.     struct utmpx utx;
  1345.  
  1346.     getutmpx(ent, &utx);
  1347.     if (host)
  1348.       strncpy(utx.ut_host, host, sizeof(utx.ut_host) );
  1349.     else
  1350.       utx.ut_host[0] = 0;
  1351.     if (user)
  1352.       strncpy(utx.ut_user, user, sizeof(utx.ut_user));
  1353.     updwtmpx(WTMPX_FILE, &utx);
  1354. #endif /* HAVE_UPDWTMPX */
  1355.  
  1356. #ifdef HAVE_UPDWTMP
  1357. #ifndef HAVE_UPDWTMPX
  1358.     /* This is already performed byupdwtmpx if present.*/
  1359.     updwtmp(WTMP_FILE, ent);
  1360. #endif /* HAVE_UPDWTMPX*/
  1361. #else /* HAVE_UPDWTMP */
  1362.  
  1363.     if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) >= 0) {
  1364.     if (!fstat(fd, &statb)) {
  1365.         memset((char *)&ut, 0, sizeof(ut));
  1366. #ifdef __hpux
  1367.         strncpy(ut.ut_id, ent->ut_id, sizeof (ut.ut_id));
  1368. #endif /* __hpux */
  1369.         strncpy(ut.ut_line, ent->ut_line, sizeof(ut.ut_line));
  1370.         strncpy(ut.ut_name, ent->ut_name, sizeof(ut.ut_name));
  1371. #ifndef NO_UT_HOST
  1372.         strncpy(ut.ut_host, ent->ut_host, sizeof(ut.ut_host));
  1373. #endif /* NO_UT_HOST */
  1374.  
  1375.         time(&uttime);
  1376.         ut.ut_time = uttime;
  1377.  
  1378. #ifdef HAVE_GETUTENT
  1379. #ifdef USER_PROCESS
  1380.         if (ent->ut_name) {
  1381.         if (!ut.ut_pid)
  1382.           ut.ut_pid = getpid();
  1383. #ifndef __hpux
  1384.         ut.ut_type = USER_PROCESS;
  1385. #else  /* __hpux */
  1386.         ut.ut_type = ent->ut_type;
  1387. #endif /* __hpux */
  1388.  
  1389.         } else {
  1390.  
  1391. #ifdef EMPTY
  1392.         ut.ut_type = EMPTY;
  1393. #else
  1394.         ut.ut_type = DEAD_PROCESS; /* For Linux brokenness*/
  1395. #endif /* EMPTY */
  1396.  
  1397.         }
  1398. #endif /* USER_PROCESS */
  1399. #endif /* HAVE_GETUTENT */
  1400.  
  1401.         if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
  1402.         sizeof(struct utmp))
  1403. #ifndef COHERENT
  1404.           ftruncate(fd, statb.st_size);
  1405. #else
  1406.           chsize(fd, statb.st_size);
  1407. #endif /* COHERENT */
  1408.     }
  1409.     close(fd);
  1410.     }
  1411. #endif /* HAVE_UPDWTMP */
  1412.     return(0); /* no current failure cases; file not found is not failure!*/
  1413. }
  1414. #endif /* WANT_UTMP */
  1415.  
  1416. static char Xline[17] = { 0, 0 };
  1417. int pty_fork_pid = -1;
  1418.  
  1419. /*
  1420.   getptyslave()
  1421.   Open the slave side of the pty, and do any initialization that is necessary.
  1422.   The return value is a file descriptor for the slave side.
  1423. */
  1424. int
  1425. getptyslave() {
  1426.     int t = -1;
  1427.     long retval;
  1428. #ifdef TIOCGWINSZ
  1429.     struct winsize ws;
  1430.     extern int cmd_rows, cmd_cols;
  1431. #endif /* TIOCGWINSZ */
  1432.  
  1433.     debug(F100,"getptyslave()","",0);
  1434.  
  1435.     /*
  1436.      * Opening the slave side may cause initilization of the
  1437.      * kernel tty structure.  We need remember the state of:
  1438.      *      if linemode was turned on
  1439.      *      terminal window size
  1440.      *      terminal speed
  1441.      * so that we can reset them if we need to.
  1442.      */
  1443.     if ((retval = pty_open_slave(Xline, &t)) != 0) {
  1444.     perror(Xline);
  1445.     msg++;
  1446.         debug(F111,"getptyslave()","Unable to open slave",retval);
  1447.         return(-1);
  1448.     }
  1449.  
  1450.     debug(F111,"getptyslave","ttyfd",ttyfd);
  1451.     debug(F111,"getptyslave","t",t);
  1452. #ifdef INIT_SPTY
  1453.     spty = t;
  1454. #endif /* INIT_SPTY */
  1455. #ifdef STREAMSPTY
  1456.     if (ioctl(t,I_PUSH,"pckt") < 0) {
  1457.         debug(F111,"getptyslave()","ioctl(I_PUSH) failed",errno);
  1458. #ifndef _AIX
  1459.         fatal("I_PUSH pckt");
  1460. #endif /* _AIX */
  1461.     }
  1462. #endif /* STREAMSPTY */
  1463.  
  1464.     /* Set up the tty modes as we like them to be. */
  1465.     init_termbuf();
  1466. #ifdef TIOCGWINSZ
  1467.     if (cmd_rows || cmd_cols) {
  1468.         memset((char *)&ws, 0, sizeof(ws));
  1469.         ws.ws_col = cmd_cols;
  1470.         ws.ws_row = cmd_rows;
  1471.         ioctl(t, TIOCSWINSZ, (char *)&ws);
  1472.     }
  1473. #endif /* TIOCGWINSZ */
  1474.  
  1475.     /* Settings for sgtty based systems */
  1476.  
  1477. #ifndef USE_TERMIO
  1478.     termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
  1479. #endif /* USE_TERMIO */
  1480.  
  1481. #ifndef OXTABS
  1482. #define OXTABS 0
  1483. #endif /* OXTABS */
  1484.  
  1485.     /* Settings for UNICOS and HPUX */
  1486.  
  1487. #ifdef CRAY
  1488.     termbuf.c_oflag = OPOST|ONLCR|TAB3;
  1489.     termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
  1490.     termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
  1491.     termbuf.c_cflag = EXTB|HUPCL|CS8;
  1492. #else /* CRAY */
  1493. #ifdef HPUX
  1494.     termbuf.c_oflag = OPOST|ONLCR|TAB3;
  1495.     termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
  1496.     termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
  1497.     termbuf.c_cflag = EXTB|HUPCL|CS8;
  1498. #else /* HPUX */
  1499. #ifdef USE_TERMIO
  1500.     /*
  1501.     Settings for all other termios/termio based systems, other than 4.4BSD.
  1502.     In 4.4BSD the kernel does the initial terminal setup.
  1503.     */
  1504. #ifdef BSD42
  1505. #ifndef BSD44
  1506.     termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG;
  1507.     termbuf.c_oflag |= ONLCR|OXTABS|OPOST;
  1508.     termbuf.c_iflag |= ICRNL|IGNPAR;
  1509.     termbuf.c_cflag |= HUPCL;
  1510.     termbuf.c_iflag &= ~IXOFF;
  1511. #endif /* BSD44 */
  1512. #else /* BSD42 */
  1513.     termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG;
  1514.     termbuf.c_oflag |= ONLCR|OXTABS|OPOST;
  1515.     termbuf.c_iflag |= ICRNL|IGNPAR;
  1516.     termbuf.c_cflag |= HUPCL;
  1517.     termbuf.c_iflag &= ~IXOFF;
  1518. #endif /* BSD42 */
  1519. #endif /* USE_TERMIO */
  1520. #endif /* HPUX */
  1521. #endif /* CRAY */
  1522.  
  1523.     set_termbuf();  /* Set the tty modes, and make this our controlling tty. */
  1524.  
  1525.     if (t != 0)
  1526.       dup2(t, 0);
  1527.     if (t != 1)
  1528.       dup2(t, 1);
  1529.     if (t != 2)
  1530.       dup2(t, 2);
  1531.     if (t > 2)
  1532.       close(t);
  1533.  
  1534.     if (ttyfd > 2) {
  1535.     close(ttyfd);
  1536.         ttyfd = -1;
  1537.     }
  1538.     return(0);
  1539. }
  1540.  
  1541. #ifdef HAVE_PTYTRAP
  1542. /*
  1543.   To be called to determine if a trap is pending on a pty
  1544.   if and only if select() cannot be used.
  1545. */
  1546. int
  1547. pty_trap_pending(fd) int fd; {
  1548.     int pending;
  1549.     int rc;
  1550.  
  1551.     rc = ioctl(fd, TIOCTRAPSTATUS, (char *)&pending, sizeof(pending));
  1552.     if (rc == 0) {
  1553.         debug(F101,"pty_trap_pending()","",pending);
  1554.         return(pending);
  1555.     } else {
  1556.         debug(F111,"pty_trap_pending()","ioctl() failed",rc);
  1557.         return(-1);
  1558.     }
  1559. }
  1560.  
  1561. /*
  1562.   To be called after select() has returned indicating that an exception is
  1563.   waiting on a pty.  It should be called with the file descriptor of the pty.
  1564.   Returns -1 on error; 0 if pty is still open; 1 if pty has closed.
  1565. */
  1566. int
  1567. pty_trap_handler(fd) int fd; {
  1568.     struct request_info ri;
  1569.  
  1570.     memset(&ri,0,sizeof(ri));
  1571.     if (ioctl(fd,TIOCREQCHECK,(char *)&ri, sizeof(ri)) != 0) {
  1572.         debug(F111,"pty_trap_handler()","ioctl(TIOCREQCHECK) failed",errno);
  1573.         return(-1);
  1574.     }
  1575.     switch (ri.request) {
  1576.       case TIOCOPEN:
  1577.         debug(F110,"pty_trap_handler()","an open() call",0);
  1578.         break;
  1579.       case TIOCCLOSE:
  1580.         debug(F110,"pty_trap_handler()","a close() call",0);
  1581.         break;
  1582.       default:
  1583.         debug(F110,"pty_trap_handler()","an ioctl() call",0);
  1584.         ri.errno_error = EINVAL;
  1585.     }
  1586.     if (ioctl(fd, TIOCREQSET, (char *)&ri,sizeof(ri)) != 0) {
  1587.         debug(F111,"pty_trap_handler()","ioctl(TIOCREQSET) failed",errno);
  1588.         return(-1);
  1589.     }
  1590.     if (ri.request == TIOCCLOSE)
  1591.       return(1);
  1592.     else
  1593.       return(0);
  1594. }
  1595. #endif /* HAVE_PTYTRAP */
  1596.  
  1597. VOID
  1598. exec_cmd(s) char * s; {
  1599.     struct stringarray * q;
  1600.     char ** args = NULL;
  1601.  
  1602.     if (!s) return;
  1603.     if (!*s) return;
  1604.  
  1605.     q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0);
  1606.     if (!q) return;
  1607.  
  1608.     args = q->a_head + 1;
  1609.     execvp(args[0],args);
  1610. }
  1611.  
  1612. /* Get a pty, scan input lines. */
  1613.  
  1614. int
  1615. do_pty(cmd) char * cmd; {
  1616.     long retval;
  1617.     int syncpipe[2];
  1618.     int i;
  1619. #ifdef HAVE_PTYTRAP
  1620.     int x;
  1621. #endif /* HAVE_PTYTRAP */
  1622.  
  1623.     msg = 0;                /* Message counter */
  1624.     pty_init();                /* Find an available pty to use. */
  1625.     errno = 0;
  1626.  
  1627.     if ((retval = pty_getpty(&ttyfd, Xline, 20)) != 0) {
  1628.     if (msg++ == 0)
  1629.       perror(Xline);
  1630.         debug(F111,"do_pty()","pty_getpty() fails",retval);
  1631.         return(-1);
  1632.     }
  1633.     debug(F110,"do_pty() Xline",Xline,0);
  1634.  
  1635. #ifdef SIGTTOU
  1636. /*
  1637.   Ignoring SIGTTOU keeps the kernel from blocking us.  we tweak the tty with
  1638.   an ioctl() (in ttioct() in /sys/tty.c in a BSD kernel)
  1639. */
  1640.      signal(SIGTTOU, SIG_IGN);
  1641. #endif /* SIGTTOU */
  1642.  
  1643. /* Start up the command on the slave side of the terminal */
  1644.  
  1645.     if (pipe(syncpipe) < 0) {
  1646.         debug(F110,"do_pty()","pipe() fails",0);
  1647.     perror("pipe() failed");
  1648.     msg++;
  1649.         debug(F111,"do_pty()","pipe fails",errno);
  1650.         return(-1);
  1651.     }
  1652.     if ((i = fork()) < 0) {
  1653.         /* XXX - need to clean up the allocated pty */
  1654.         perror("fork() failed");
  1655.     msg++;
  1656.         debug(F111,"do_pty()","fork fails",errno);
  1657.         return(-1);
  1658.     }
  1659.     if (i) {  /* Wait for child before writing to parent side of pty. */
  1660.         char c;
  1661. #ifdef HAVE_PTYTRAP
  1662.         int on = 1;
  1663. #endif /* HAVE_PTYTRAP */
  1664.     close(syncpipe[1]);
  1665.     errno = 0;
  1666.         if (read(syncpipe[0], &c, 1) == 0) { /* Slave side died */
  1667.         perror("Pipe read() failed");
  1668.         msg++;
  1669.             debug(F110,"do_pty()","Slave fails to initialize",0);
  1670.             close(syncpipe[0]);
  1671.             return(-1);
  1672.         }
  1673.         pty_fork_pid = i;        /* So we can clean it up later */
  1674.     debug(F101,"do_pty pty_fork_pid","",pty_fork_pid);
  1675. #ifdef HAVE_PTYTRAP
  1676.         /* HPUX does not allow the master to read end of file.  */
  1677.         /* Therefore, we must determine that the slave has been */
  1678.         /* closed by trapping the call to close().              */
  1679.     errno = 0;
  1680.     x = ioctl(ttyfd, TIOCTRAP, (char *)&on);
  1681.     debug(F111,"do_pty ioctl(TIOCTRAP)",ckitoa(x),errno);
  1682. #endif /* HAVE_PTYTRAP */
  1683.         debug(F111,"do_pty()","synchronized - pty_fork_pid",pty_fork_pid);
  1684.         close(syncpipe[0]);
  1685.     } else {
  1686.         debug(F110,"do_pty()","Slave starts",0);
  1687.         if (getptyslave() == 0) {
  1688. #ifdef WANT_UTMP
  1689.             pty_update_utmp(PTY_USER_PROCESS,
  1690.                 getpid(),
  1691.                 "KERMIT",
  1692.                 Xline,
  1693.                 cmd,
  1694.                 PTY_TTYSLOT_USABLE
  1695.                 );
  1696. #endif /* WANT_UTMP */
  1697.             /* Notify our parent we're ready to continue.*/
  1698.             debug(F110,"do_pty()","slave synchronizing",0);
  1699.             write(syncpipe[1],"y",1);
  1700.             close(syncpipe[0]);
  1701.             close(syncpipe[1]);
  1702.  
  1703.             exec_cmd(cmd);
  1704.             debug(F111,"do_pty()","exec_cmd() returns - why?",errno);
  1705.         }
  1706.         debug(F110,"do_pty()","getptyslave() fails - exiting",0);
  1707.         exit(1);
  1708.     }
  1709.     return(0);
  1710. } /* end of do_pty() */
  1711.  
  1712.  
  1713. VOID
  1714. end_pty() {
  1715.     msg = 0;                /* Message counter */
  1716.     if (Xline[0] && pty_fork_pid >= 0) {
  1717.         pty_cleanup(Xline,pty_fork_pid,1);
  1718.         Xline[0] = '\0';
  1719.         pty_fork_pid = -1;
  1720.     }
  1721. }
  1722. #endif /* NETPTY */
  1723.