limit total running time for getty to prevent bad lines from forcing getty
[unix-history] / usr / src / libexec / telnetd / sys_term.c
CommitLineData
ea139302 1/*
4eb3b9d6
KB
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
ea139302 4 *
836fe169 5 * %sccs.include.redist.c%
ea139302
PB
6 */
7
8#ifndef lint
4eb3b9d6 9static char sccsid[] = "@(#)sys_term.c 8.1 (Berkeley) %G%";
ea139302
PB
10#endif /* not lint */
11
12#include "telnetd.h"
13#include "pathnames.h"
14
8832c633 15#if defined(AUTHENTICATION)
1af3d848
DB
16#include <libtelnet/auth.h>
17#endif
18
258d091a
DB
19#if defined(CRAY) || defined(__hpux)
20# define PARENT_DOES_UTMP
21#endif
22
ea139302
PB
23#ifdef NEWINIT
24#include <initreq.h>
258d091a 25int utmp_len = MAXHOSTNAMELEN; /* sizeof(init_request.host) */
ea139302 26#else /* NEWINIT*/
8832c633
DB
27# ifdef UTMPX
28# include <utmpx.h>
29# else
30# include <utmp.h>
31# endif /* UTMPX */
ea139302
PB
32struct utmp wtmp;
33
8832c633 34int utmp_len = sizeof(wtmp.ut_host);
258d091a 35# ifndef PARENT_DOES_UTMP
ea139302
PB
36char wtmpf[] = "/usr/adm/wtmp";
37char utmpf[] = "/etc/utmp";
258d091a 38# else /* PARENT_DOES_UTMP */
ea139302 39char wtmpf[] = "/etc/wtmp";
258d091a
DB
40# endif /* PARENT_DOES_UTMP */
41
42# ifdef CRAY
1af3d848
DB
43#include <tmpdir.h>
44#include <sys/wait.h>
258d091a
DB
45# if defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY)
46 /*
47 * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can
48 * use it to tell us to turn off all the socket security code,
49 * since that is only used in UNICOS 7.0 and later.
50 */
51# undef _SC_CRAY_SECURE_SYS
52# endif
53
8832c633
DB
54# if defined(_SC_CRAY_SECURE_SYS)
55#include <sys/sysv.h>
56#include <sys/secstat.h>
57extern int secflag;
58extern struct sysv sysv;
59# endif /* _SC_CRAY_SECURE_SYS */
ea139302
PB
60# endif /* CRAY */
61#endif /* NEWINIT */
62
8832c633
DB
63#ifdef STREAMSPTY
64#include <sac.h>
65#include <sys/stropts.h>
66#endif
67
ea139302
PB
68#define SCPYN(a, b) (void) strncpy(a, b, sizeof(a))
69#define SCMPN(a, b) strncmp(a, b, sizeof(a))
70
4a8a7128
PB
71#ifdef STREAMS
72#include <sys/stream.h>
73#endif
258d091a
DB
74#ifdef __hpux
75#include <sys/resource.h>
76#include <sys/proc.h>
77#endif
ea139302
PB
78#include <sys/tty.h>
79#ifdef t_erase
80#undef t_erase
81#undef t_kill
82#undef t_intrc
83#undef t_quitc
84#undef t_startc
85#undef t_stopc
86#undef t_eofc
87#undef t_brkc
88#undef t_suspc
89#undef t_dsuspc
90#undef t_rprntc
91#undef t_flushc
92#undef t_werasc
93#undef t_lnextc
94#endif
95
4a8a7128
PB
96#if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC)
97# define EXTPROC 0400
98#endif
99
ea139302
PB
100#ifndef USE_TERMIO
101struct termbuf {
102 struct sgttyb sg;
103 struct tchars tc;
104 struct ltchars ltc;
105 int state;
106 int lflags;
107} termbuf, termbuf2;
2c9c7136
PB
108# define cfsetospeed(tp, val) (tp)->sg.sg_ospeed = (val)
109# define cfsetispeed(tp, val) (tp)->sg.sg_ispeed = (val)
1af3d848
DB
110# define cfgetospeed(tp) (tp)->sg.sg_ospeed
111# define cfgetispeed(tp) (tp)->sg.sg_ispeed
ea139302 112#else /* USE_TERMIO */
ea139302
PB
113# ifdef SYSV_TERMIO
114# define termios termio
115# endif
2c9c7136 116# ifndef TCSANOW
4a8a7128 117# ifdef TCSETS
2c9c7136
PB
118# define TCSANOW TCSETS
119# define TCSADRAIN TCSETSW
1af3d848 120# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
4a8a7128 121# else
2c9c7136
PB
122# ifdef TCSETA
123# define TCSANOW TCSETA
124# define TCSADRAIN TCSETAW
1af3d848 125# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
2c9c7136
PB
126# else
127# define TCSANOW TIOCSETA
128# define TCSADRAIN TIOCSETAW
1af3d848 129# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
2c9c7136 130# endif
4a8a7128 131# endif
2c9c7136
PB
132# define tcsetattr(f, a, t) ioctl(f, a, t)
133# define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
134 (tp)->c_cflag |= (val)
1af3d848 135# define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
2c9c7136
PB
136# ifdef CIBAUD
137# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
138 (tp)->c_cflag |= ((val)<<IBSHIFT)
1af3d848 139# define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
2c9c7136
PB
140# else
141# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
142 (tp)->c_cflag |= (val)
1af3d848 143# define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
2c9c7136
PB
144# endif
145# endif /* TCSANOW */
ea139302 146struct termios termbuf, termbuf2; /* pty control structure */
54115ffd 147# ifdef STREAMSPTY
8832c633 148int ttyfd = -1;
54115ffd 149# endif
ea139302
PB
150#endif /* USE_TERMIO */
151
152/*
153 * init_termbuf()
154 * copy_termbuf(cp)
155 * set_termbuf()
156 *
157 * These three routines are used to get and set the "termbuf" structure
158 * to and from the kernel. init_termbuf() gets the current settings.
159 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
160 * set_termbuf() writes the structure into the kernel.
161 */
162
1af3d848 163 void
ea139302
PB
164init_termbuf()
165{
166#ifndef USE_TERMIO
167 (void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg);
168 (void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc);
169 (void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc);
170# ifdef TIOCGSTATE
171 (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
172# endif
173#else
54115ffd 174# ifdef STREAMSPTY
8832c633 175 (void) tcgetattr(ttyfd, &termbuf);
54115ffd
DB
176# else
177 (void) tcgetattr(pty, &termbuf);
178# endif
ea139302
PB
179#endif
180 termbuf2 = termbuf;
181}
182
183#if defined(LINEMODE) && defined(TIOCPKT_IOCTL)
1af3d848 184 void
ea139302 185copy_termbuf(cp, len)
1af3d848
DB
186 char *cp;
187 int len;
ea139302
PB
188{
189 if (len > sizeof(termbuf))
190 len = sizeof(termbuf);
191 bcopy(cp, (char *)&termbuf, len);
192 termbuf2 = termbuf;
193}
194#endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
195
1af3d848 196 void
ea139302
PB
197set_termbuf()
198{
199 /*
200 * Only make the necessary changes.
201 */
202#ifndef USE_TERMIO
203 if (bcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
2c9c7136 204 (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg);
ea139302
PB
205 if (bcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
206 (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
207 if (bcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
208 sizeof(termbuf.ltc)))
209 (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
210 if (termbuf.lflags != termbuf2.lflags)
211 (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
212#else /* USE_TERMIO */
213 if (bcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
54115ffd 214# ifdef STREAMSPTY
8832c633 215 (void) tcsetattr(ttyfd, TCSANOW, &termbuf);
54115ffd
DB
216# else
217 (void) tcsetattr(pty, TCSANOW, &termbuf);
218# endif
8832c633 219# if defined(CRAY2) && defined(UNICOS5)
ea139302
PB
220 needtermstat = 1;
221# endif
222#endif /* USE_TERMIO */
223}
224
225
226/*
227 * spcset(func, valp, valpp)
228 *
229 * This function takes various special characters (func), and
230 * sets *valp to the current value of that character, and
231 * *valpp to point to where in the "termbuf" structure that
232 * value is kept.
233 *
234 * It returns the SLC_ level of support for this function.
235 */
236
237#ifndef USE_TERMIO
1af3d848 238 int
ea139302 239spcset(func, valp, valpp)
1af3d848
DB
240 int func;
241 cc_t *valp;
242 cc_t **valpp;
ea139302
PB
243{
244 switch(func) {
245 case SLC_EOF:
246 *valp = termbuf.tc.t_eofc;
ed8f31c1 247 *valpp = (cc_t *)&termbuf.tc.t_eofc;
ea139302
PB
248 return(SLC_VARIABLE);
249 case SLC_EC:
250 *valp = termbuf.sg.sg_erase;
ed8f31c1 251 *valpp = (cc_t *)&termbuf.sg.sg_erase;
ea139302
PB
252 return(SLC_VARIABLE);
253 case SLC_EL:
254 *valp = termbuf.sg.sg_kill;
ed8f31c1 255 *valpp = (cc_t *)&termbuf.sg.sg_kill;
ea139302
PB
256 return(SLC_VARIABLE);
257 case SLC_IP:
258 *valp = termbuf.tc.t_intrc;
ed8f31c1 259 *valpp = (cc_t *)&termbuf.tc.t_intrc;
ea139302
PB
260 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
261 case SLC_ABORT:
262 *valp = termbuf.tc.t_quitc;
ed8f31c1 263 *valpp = (cc_t *)&termbuf.tc.t_quitc;
ea139302
PB
264 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
265 case SLC_XON:
266 *valp = termbuf.tc.t_startc;
ed8f31c1 267 *valpp = (cc_t *)&termbuf.tc.t_startc;
ea139302
PB
268 return(SLC_VARIABLE);
269 case SLC_XOFF:
270 *valp = termbuf.tc.t_stopc;
ed8f31c1 271 *valpp = (cc_t *)&termbuf.tc.t_stopc;
ea139302
PB
272 return(SLC_VARIABLE);
273 case SLC_AO:
274 *valp = termbuf.ltc.t_flushc;
ed8f31c1 275 *valpp = (cc_t *)&termbuf.ltc.t_flushc;
ea139302
PB
276 return(SLC_VARIABLE);
277 case SLC_SUSP:
278 *valp = termbuf.ltc.t_suspc;
ed8f31c1 279 *valpp = (cc_t *)&termbuf.ltc.t_suspc;
ea139302
PB
280 return(SLC_VARIABLE);
281 case SLC_EW:
282 *valp = termbuf.ltc.t_werasc;
ed8f31c1 283 *valpp = (cc_t *)&termbuf.ltc.t_werasc;
ea139302
PB
284 return(SLC_VARIABLE);
285 case SLC_RP:
286 *valp = termbuf.ltc.t_rprntc;
ed8f31c1 287 *valpp = (cc_t *)&termbuf.ltc.t_rprntc;
ea139302
PB
288 return(SLC_VARIABLE);
289 case SLC_LNEXT:
290 *valp = termbuf.ltc.t_lnextc;
ed8f31c1
PB
291 *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
292 return(SLC_VARIABLE);
293 case SLC_FORW1:
294 *valp = termbuf.tc.t_brkc;
295 *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
ea139302
PB
296 return(SLC_VARIABLE);
297 case SLC_BRK:
298 case SLC_SYNCH:
299 case SLC_AYT:
300 case SLC_EOR:
ed8f31c1
PB
301 *valp = (cc_t)0;
302 *valpp = (cc_t *)0;
ea139302
PB
303 return(SLC_DEFAULT);
304 default:
ed8f31c1
PB
305 *valp = (cc_t)0;
306 *valpp = (cc_t *)0;
ea139302
PB
307 return(SLC_NOSUPPORT);
308 }
309}
310
311#else /* USE_TERMIO */
312
1af3d848 313 int
ea139302 314spcset(func, valp, valpp)
1af3d848
DB
315 int func;
316 cc_t *valp;
317 cc_t **valpp;
ea139302 318{
053fd49d
PB
319
320#define setval(a, b) *valp = termbuf.c_cc[a]; \
321 *valpp = &termbuf.c_cc[a]; \
322 return(b);
ed8f31c1 323#define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
053fd49d 324
ea139302
PB
325 switch(func) {
326 case SLC_EOF:
053fd49d 327 setval(VEOF, SLC_VARIABLE);
ea139302 328 case SLC_EC:
053fd49d 329 setval(VERASE, SLC_VARIABLE);
ea139302 330 case SLC_EL:
053fd49d 331 setval(VKILL, SLC_VARIABLE);
ea139302 332 case SLC_IP:
053fd49d 333 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
ea139302 334 case SLC_ABORT:
053fd49d 335 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
ea139302 336 case SLC_XON:
053fd49d
PB
337#ifdef VSTART
338 setval(VSTART, SLC_VARIABLE);
339#else
340 defval(0x13);
341#endif
ea139302 342 case SLC_XOFF:
053fd49d
PB
343#ifdef VSTOP
344 setval(VSTOP, SLC_VARIABLE);
345#else
346 defval(0x11);
347#endif
ea139302 348 case SLC_EW:
053fd49d
PB
349#ifdef VWERASE
350 setval(VWERASE, SLC_VARIABLE);
351#else
352 defval(0);
353#endif
ea139302 354 case SLC_RP:
053fd49d
PB
355#ifdef VREPRINT
356 setval(VREPRINT, SLC_VARIABLE);
357#else
358 defval(0);
359#endif
ea139302 360 case SLC_LNEXT:
053fd49d
PB
361#ifdef VLNEXT
362 setval(VLNEXT, SLC_VARIABLE);
363#else
364 defval(0);
365#endif
366 case SLC_AO:
2c9c7136
PB
367#if !defined(VDISCARD) && defined(VFLUSHO)
368# define VDISCARD VFLUSHO
369#endif
370#ifdef VDISCARD
371 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
053fd49d
PB
372#else
373 defval(0);
374#endif
375 case SLC_SUSP:
376#ifdef VSUSP
377 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
378#else
379 defval(0);
380#endif
ed8f31c1
PB
381#ifdef VEOL
382 case SLC_FORW1:
383 setval(VEOL, SLC_VARIABLE);
384#endif
385#ifdef VEOL2
386 case SLC_FORW2:
387 setval(VEOL2, SLC_VARIABLE);
388#endif
2c9c7136
PB
389 case SLC_AYT:
390#ifdef VSTATUS
391 setval(VSTATUS, SLC_VARIABLE);
392#else
393 defval(0);
394#endif
053fd49d 395
ea139302
PB
396 case SLC_BRK:
397 case SLC_SYNCH:
ea139302 398 case SLC_EOR:
053fd49d
PB
399 defval(0);
400
ea139302
PB
401 default:
402 *valp = 0;
403 *valpp = 0;
404 return(SLC_NOSUPPORT);
405 }
406}
407#endif /* USE_TERMIO */
408
ed8f31c1
PB
409#ifdef CRAY
410/*
411 * getnpty()
412 *
413 * Return the number of pty's configured into the system.
414 */
1af3d848 415 int
ed8f31c1
PB
416getnpty()
417{
418#ifdef _SC_CRAY_NPTY
1af3d848
DB
419 int numptys;
420
421 if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
422 return numptys;
423 else
ed8f31c1 424#endif /* _SC_CRAY_NPTY */
1af3d848 425 return 128;
ed8f31c1
PB
426}
427#endif /* CRAY */
428
2c9c7136 429#ifndef convex
ea139302
PB
430/*
431 * getpty()
432 *
433 * Allocate a pty. As a side effect, the external character
434 * array "line" contains the name of the slave side.
435 *
436 * Returns the file descriptor of the opened pty.
437 */
2c9c7136 438#ifndef __GNUC__
ea139302 439char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
2c9c7136
PB
440#else
441static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
442char *line = Xline;
443#endif
444#ifdef CRAY
445char *myline = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
446#endif /* CRAY */
ea139302 447
1af3d848 448 int
258d091a
DB
449getpty(ptynum)
450int *ptynum;
ea139302
PB
451{
452 register int p;
8832c633
DB
453#ifdef STREAMSPTY
454 int t;
455 char *ptsname();
456
457 p = open("/dev/ptmx", 2);
458 if (p > 0) {
459 grantpt(p);
460 unlockpt(p);
461 strcpy(line, ptsname(p));
462 return(p);
463 }
464
465#else /* ! STREAMSPTY */
ea139302 466#ifndef CRAY
8832c633 467 register char *cp, *p1, *p2;
ea139302 468 register int i;
4d212406 469#if defined(sun) && defined(TIOCGPGRP) && BSD < 199207
8832c633
DB
470 int dummy;
471#endif
ea139302 472
258d091a 473#ifndef __hpux
ea139302
PB
474 (void) sprintf(line, "/dev/ptyXX");
475 p1 = &line[8];
476 p2 = &line[9];
258d091a
DB
477#else
478 (void) sprintf(line, "/dev/ptym/ptyXX");
479 p1 = &line[13];
480 p2 = &line[14];
481#endif
ea139302 482
8832c633 483 for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
ea139302
PB
484 struct stat stb;
485
8832c633 486 *p1 = *cp;
ea139302 487 *p2 = '0';
8832c633
DB
488 /*
489 * This stat() check is just to keep us from
490 * looping through all 256 combinations if there
491 * aren't that many ptys available.
492 */
ea139302
PB
493 if (stat(line, &stb) < 0)
494 break;
495 for (i = 0; i < 16; i++) {
496 *p2 = "0123456789abcdef"[i];
497 p = open(line, 2);
498 if (p > 0) {
258d091a 499#ifndef __hpux
ea139302 500 line[5] = 't';
258d091a
DB
501#else
502 for (p1 = &line[8]; *p1; p1++)
503 *p1 = *(p1+1);
504 line[9] = 't';
505#endif
8832c633
DB
506 chown(line, 0, 0);
507 chmod(line, 0600);
4d212406 508#if defined(sun) && defined(TIOCGPGRP) && BSD < 199207
8832c633
DB
509 if (ioctl(p, TIOCGPGRP, &dummy) == 0
510 || errno != EIO) {
511 chmod(line, 0666);
512 close(p);
513 line[5] = 'p';
514 } else
4d212406 515#endif /* defined(sun) && defined(TIOCGPGRP) && BSD < 199207 */
8832c633 516 return(p);
ea139302
PB
517 }
518 }
519 }
520#else /* CRAY */
ea139302 521 extern lowpty, highpty;
2c9c7136 522 struct stat sb;
ea139302 523
258d091a
DB
524 for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {
525 (void) sprintf(myline, "/dev/pty/%03d", *ptynum);
2c9c7136 526 p = open(myline, 2);
ea139302
PB
527 if (p < 0)
528 continue;
258d091a 529 (void) sprintf(line, "/dev/ttyp%03d", *ptynum);
2c9c7136
PB
530 /*
531 * Here are some shenanigans to make sure that there
532 * are no listeners lurking on the line.
533 */
534 if(stat(line, &sb) < 0) {
535 (void) close(p);
536 continue;
537 }
538 if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
539 chown(line, 0, 0);
540 chmod(line, 0600);
541 (void)close(p);
542 p = open(myline, 2);
543 if (p < 0)
544 continue;
545 }
546 /*
547 * Now it should be safe...check for accessability.
548 */
ea139302
PB
549 if (access(line, 6) == 0)
550 return(p);
551 else {
552 /* no tty side to pty so skip it */
553 (void) close(p);
554 }
555 }
556#endif /* CRAY */
8832c633 557#endif /* STREAMSPTY */
ea139302
PB
558 return(-1);
559}
2c9c7136 560#endif /* convex */
ea139302
PB
561
562#ifdef LINEMODE
563/*
564 * tty_flowmode() Find out if flow control is enabled or disabled.
565 * tty_linemode() Find out if linemode (external processing) is enabled.
566 * tty_setlinemod(on) Turn on/off linemode.
567 * tty_isecho() Find out if echoing is turned on.
568 * tty_setecho(on) Enable/disable character echoing.
569 * tty_israw() Find out if terminal is in RAW mode.
570 * tty_binaryin(on) Turn on/off BINARY on input.
571 * tty_binaryout(on) Turn on/off BINARY on output.
572 * tty_isediting() Find out if line editing is enabled.
573 * tty_istrapsig() Find out if signal trapping is enabled.
574 * tty_setedit(on) Turn on/off line editing.
575 * tty_setsig(on) Turn on/off signal trapping.
4a8a7128
PB
576 * tty_issofttab() Find out if tab expansion is enabled.
577 * tty_setsofttab(on) Turn on/off soft tab expansion.
578 * tty_islitecho() Find out if typed control chars are echoed literally
579 * tty_setlitecho() Turn on/off literal echo of control chars
ea139302
PB
580 * tty_tspeed(val) Set transmit speed to val.
581 * tty_rspeed(val) Set receive speed to val.
582 */
583
2c9c7136
PB
584#ifdef convex
585static int linestate;
586#endif
587
1af3d848 588 int
ea139302
PB
589tty_linemode()
590{
2c9c7136 591#ifndef convex
ea139302
PB
592#ifndef USE_TERMIO
593 return(termbuf.state & TS_EXTPROC);
594#else
595 return(termbuf.c_lflag & EXTPROC);
596#endif
2c9c7136
PB
597#else
598 return(linestate);
599#endif
ea139302
PB
600}
601
1af3d848 602 void
ea139302 603tty_setlinemode(on)
1af3d848 604 int on;
ea139302
PB
605{
606#ifdef TIOCEXT
2c9c7136
PB
607# ifndef convex
608 set_termbuf();
609# else
610 linestate = on;
611# endif
ea139302 612 (void) ioctl(pty, TIOCEXT, (char *)&on);
2c9c7136
PB
613# ifndef convex
614 init_termbuf();
615# endif
ea139302 616#else /* !TIOCEXT */
2c9c7136 617# ifdef EXTPROC
ea139302
PB
618 if (on)
619 termbuf.c_lflag |= EXTPROC;
620 else
621 termbuf.c_lflag &= ~EXTPROC;
2c9c7136 622# endif
ea139302
PB
623#endif /* TIOCEXT */
624}
625
1af3d848 626 int
ea139302
PB
627tty_isecho()
628{
629#ifndef USE_TERMIO
630 return (termbuf.sg.sg_flags & ECHO);
631#else
632 return (termbuf.c_lflag & ECHO);
633#endif
634}
635#endif /* LINEMODE */
636
1d23bbc4
DB
637 int
638tty_flowmode()
639{
640#ifndef USE_TERMIO
641 return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
642#else
643 return((termbuf.c_iflag & IXON) ? 1 : 0);
644#endif
645}
646
647 int
648tty_restartany()
649{
650#ifndef USE_TERMIO
651# ifdef DECCTQ
652 return((termbuf.lflags & DECCTQ) ? 0 : 1);
653# else
654 return(-1);
655# endif
656#else
657 return((termbuf.c_iflag & IXANY) ? 1 : 0);
658#endif
659}
660
1af3d848 661 void
ea139302 662tty_setecho(on)
1af3d848 663 int on;
ea139302
PB
664{
665#ifndef USE_TERMIO
666 if (on)
667 termbuf.sg.sg_flags |= ECHO|CRMOD;
668 else
669 termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
670#else
671 if (on)
672 termbuf.c_lflag |= ECHO;
673 else
674 termbuf.c_lflag &= ~ECHO;
675#endif
676}
677
678#if defined(LINEMODE) && defined(KLUDGELINEMODE)
1af3d848 679 int
ea139302
PB
680tty_israw()
681{
682#ifndef USE_TERMIO
683 return(termbuf.sg.sg_flags & RAW);
684#else
685 return(!(termbuf.c_lflag & ICANON));
686#endif
687}
688#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
689
1af3d848 690 void
ea139302 691tty_binaryin(on)
1af3d848 692 int on;
ea139302
PB
693{
694#ifndef USE_TERMIO
695 if (on)
696 termbuf.lflags |= LPASS8;
697 else
698 termbuf.lflags &= ~LPASS8;
699#else
700 if (on) {
1af3d848 701 termbuf.c_iflag &= ~ISTRIP;
ea139302 702 } else {
1af3d848 703 termbuf.c_iflag |= ISTRIP;
ea139302
PB
704 }
705#endif
706}
707
1af3d848 708 void
ea139302 709tty_binaryout(on)
1af3d848 710 int on;
ea139302
PB
711{
712#ifndef USE_TERMIO
713 if (on)
714 termbuf.lflags |= LLITOUT;
715 else
716 termbuf.lflags &= ~LLITOUT;
717#else
718 if (on) {
719 termbuf.c_cflag &= ~(CSIZE|PARENB);
720 termbuf.c_cflag |= CS8;
721 termbuf.c_oflag &= ~OPOST;
722 } else {
723 termbuf.c_cflag &= ~CSIZE;
724 termbuf.c_cflag |= CS7|PARENB;
725 termbuf.c_oflag |= OPOST;
726 }
727#endif
728}
729
1af3d848 730 int
ea139302
PB
731tty_isbinaryin()
732{
733#ifndef USE_TERMIO
734 return(termbuf.lflags & LPASS8);
735#else
053fd49d 736 return(!(termbuf.c_iflag & ISTRIP));
ea139302
PB
737#endif
738}
739
1af3d848 740 int
ea139302
PB
741tty_isbinaryout()
742{
743#ifndef USE_TERMIO
744 return(termbuf.lflags & LLITOUT);
745#else
053fd49d 746 return(!(termbuf.c_oflag&OPOST));
ea139302
PB
747#endif
748}
749
750#ifdef LINEMODE
1af3d848 751 int
ea139302
PB
752tty_isediting()
753{
754#ifndef USE_TERMIO
755 return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
756#else
757 return(termbuf.c_lflag & ICANON);
758#endif
759}
760
1af3d848 761 int
ea139302
PB
762tty_istrapsig()
763{
764#ifndef USE_TERMIO
765 return(!(termbuf.sg.sg_flags&RAW));
766#else
767 return(termbuf.c_lflag & ISIG);
768#endif
769}
770
1af3d848 771 void
ea139302 772tty_setedit(on)
1af3d848 773 int on;
ea139302
PB
774{
775#ifndef USE_TERMIO
776 if (on)
777 termbuf.sg.sg_flags &= ~CBREAK;
778 else
779 termbuf.sg.sg_flags |= CBREAK;
780#else
781 if (on)
782 termbuf.c_lflag |= ICANON;
783 else
784 termbuf.c_lflag &= ~ICANON;
785#endif
786}
787
1af3d848 788 void
ea139302 789tty_setsig(on)
1af3d848 790 int on;
ea139302
PB
791{
792#ifndef USE_TERMIO
793 if (on)
794 ;
795#else
796 if (on)
797 termbuf.c_lflag |= ISIG;
798 else
799 termbuf.c_lflag &= ~ISIG;
800#endif
801}
802#endif /* LINEMODE */
803
1af3d848 804 int
4a8a7128
PB
805tty_issofttab()
806{
807#ifndef USE_TERMIO
808 return (termbuf.sg.sg_flags & XTABS);
809#else
810# ifdef OXTABS
811 return (termbuf.c_oflag & OXTABS);
812# endif
813# ifdef TABDLY
814 return ((termbuf.c_oflag & TABDLY) == TAB3);
815# endif
816#endif
817}
818
1af3d848 819 void
4a8a7128 820tty_setsofttab(on)
1af3d848 821 int on;
4a8a7128
PB
822{
823#ifndef USE_TERMIO
824 if (on)
825 termbuf.sg.sg_flags |= XTABS;
826 else
827 termbuf.sg.sg_flags &= ~XTABS;
828#else
829 if (on) {
830# ifdef OXTABS
831 termbuf.c_oflag |= OXTABS;
832# endif
833# ifdef TABDLY
834 termbuf.c_oflag &= ~TABDLY;
835 termbuf.c_oflag |= TAB3;
836# endif
837 } else {
838# ifdef OXTABS
839 termbuf.c_oflag &= ~OXTABS;
840# endif
841# ifdef TABDLY
842 termbuf.c_oflag &= ~TABDLY;
843 termbuf.c_oflag |= TAB0;
844# endif
845 }
846#endif
847}
848
1af3d848 849 int
4a8a7128
PB
850tty_islitecho()
851{
852#ifndef USE_TERMIO
1af3d848 853 return (!(termbuf.lflags & LCTLECH));
4a8a7128
PB
854#else
855# ifdef ECHOCTL
856 return (!(termbuf.c_lflag & ECHOCTL));
857# endif
858# ifdef TCTLECH
859 return (!(termbuf.c_lflag & TCTLECH));
860# endif
861# if !defined(ECHOCTL) && !defined(TCTLECH)
862 return (0); /* assumes ctl chars are echoed '^x' */
863# endif
864#endif
865}
866
1af3d848 867 void
4a8a7128 868tty_setlitecho(on)
1af3d848 869 int on;
4a8a7128
PB
870{
871#ifndef USE_TERMIO
872 if (on)
1af3d848 873 termbuf.lflags &= ~LCTLECH;
4a8a7128 874 else
1af3d848 875 termbuf.lflags |= LCTLECH;
4a8a7128
PB
876#else
877# ifdef ECHOCTL
878 if (on)
879 termbuf.c_lflag &= ~ECHOCTL;
880 else
881 termbuf.c_lflag |= ECHOCTL;
882# endif
883# ifdef TCTLECH
884 if (on)
885 termbuf.c_lflag &= ~TCTLECH;
886 else
887 termbuf.c_lflag |= TCTLECH;
888# endif
889#endif
1af3d848
DB
890}
891
892 int
893tty_iscrnl()
894{
895#ifndef USE_TERMIO
896 return (termbuf.sg.sg_flags & CRMOD);
897#else
898 return (termbuf.c_iflag & ICRNL);
899#endif
4a8a7128
PB
900}
901
ea139302
PB
902/*
903 * A table of available terminal speeds
904 */
905struct termspeeds {
906 int speed;
907 int value;
908} termspeeds[] = {
909 { 0, B0 }, { 50, B50 }, { 75, B75 },
910 { 110, B110 }, { 134, B134 }, { 150, B150 },
911 { 200, B200 }, { 300, B300 }, { 600, B600 },
912 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
913 { 4800, B4800 }, { 9600, B9600 }, { 19200, B9600 },
914 { 38400, B9600 }, { -1, B9600 }
915};
916
1af3d848 917 void
ea139302 918tty_tspeed(val)
1af3d848 919 int val;
ea139302
PB
920{
921 register struct termspeeds *tp;
922
923 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
924 ;
2c9c7136 925 cfsetospeed(&termbuf, tp->value);
ea139302
PB
926}
927
1af3d848 928 void
ea139302 929tty_rspeed(val)
1af3d848 930 int val;
ea139302
PB
931{
932 register struct termspeeds *tp;
933
934 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
935 ;
2c9c7136 936 cfsetispeed(&termbuf, tp->value);
ea139302
PB
937}
938
ed8f31c1 939#if defined(CRAY2) && defined(UNICOS5)
1af3d848 940 int
ea139302
PB
941tty_isnewmap()
942{
943 return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) &&
944 !(termbuf.c_oflag & ONLRET));
945}
946#endif
947
258d091a 948#ifdef PARENT_DOES_UTMP
ea139302
PB
949# ifndef NEWINIT
950extern struct utmp wtmp;
951extern char wtmpf[];
952# else /* NEWINIT */
953int gotalarm;
1af3d848
DB
954
955 /* ARGSUSED */
956 void
ed8f31c1 957nologinproc(sig)
1af3d848 958 int sig;
ea139302
PB
959{
960 gotalarm++;
961}
962# endif /* NEWINIT */
258d091a 963#endif /* PARENT_DOES_UTMP */
ea139302 964
1af3d848 965#ifndef NEWINIT
258d091a 966# ifdef PARENT_DOES_UTMP
1af3d848
DB
967extern void utmp_sig_init P((void));
968extern void utmp_sig_reset P((void));
969extern void utmp_sig_wait P((void));
970extern void utmp_sig_notify P((int));
258d091a 971# endif /* PARENT_DOES_UTMP */
1af3d848
DB
972#endif
973
ea139302
PB
974/*
975 * getptyslave()
976 *
977 * Open the slave side of the pty, and do any initialization
978 * that is necessary. The return value is a file descriptor
979 * for the slave side.
980 */
1af3d848 981 int
ea139302
PB
982getptyslave()
983{
984 register int t = -1;
985
2c9c7136
PB
986#if !defined(CRAY) || !defined(NEWINIT)
987# ifdef LINEMODE
1af3d848
DB
988 int waslm;
989# endif
990# ifdef TIOCGWINSZ
991 struct winsize ws;
992 extern int def_row, def_col;
993# endif
994 extern int def_tspeed, def_rspeed;
ea139302 995 /*
2c9c7136 996 * Opening the slave side may cause initilization of the
1af3d848
DB
997 * kernel tty structure. We need remember the state of
998 * if linemode was turned on
999 * terminal window size
1000 * terminal speed
1001 * so that we can re-set them if we need to.
ea139302 1002 */
1af3d848
DB
1003# ifdef LINEMODE
1004 waslm = tty_linemode();
2c9c7136
PB
1005# endif
1006
1007
1008 /*
1009 * Make sure that we don't have a controlling tty, and
1010 * that we are the session (process group) leader.
1011 */
1012# ifdef TIOCNOTTY
ea139302
PB
1013 t = open(_PATH_TTY, O_RDWR);
1014 if (t >= 0) {
1015 (void) ioctl(t, TIOCNOTTY, (char *)0);
1016 (void) close(t);
1017 }
2c9c7136 1018# endif
ea139302 1019
2c9c7136 1020
258d091a 1021# ifdef PARENT_DOES_UTMP
2c9c7136
PB
1022 /*
1023 * Wait for our parent to get the utmp stuff to get done.
1024 */
1025 utmp_sig_wait();
1026# endif
1027
1028 t = cleanopen(line);
ea139302
PB
1029 if (t < 0)
1030 fatalperror(net, line);
1031
54115ffd 1032#ifdef STREAMSPTY
8832c633
DB
1033#ifdef USE_TERMIO
1034 ttyfd = t;
1035#endif
8832c633
DB
1036 if (ioctl(t, I_PUSH, "ptem") < 0)
1037 fatal(net, "I_PUSH ptem");
1038 if (ioctl(t, I_PUSH, "ldterm") < 0)
1039 fatal(net, "I_PUSH ldterm");
1040 if (ioctl(t, I_PUSH, "ttcompat") < 0)
1041 fatal(net, "I_PUSH ttcompat");
1042 if (ioctl(pty, I_PUSH, "pckt") < 0)
1043 fatal(net, "I_PUSH pckt");
1044#endif
1045
2c9c7136
PB
1046 /*
1047 * set up the tty modes as we like them to be.
1048 */
ea139302 1049 init_termbuf();
1af3d848
DB
1050# ifdef TIOCGWINSZ
1051 if (def_row || def_col) {
1052 bzero((char *)&ws, sizeof(ws));
1053 ws.ws_col = def_col;
1054 ws.ws_row = def_row;
1055 (void)ioctl(t, TIOCSWINSZ, (char *)&ws);
1056 }
1057# endif
2c9c7136
PB
1058
1059 /*
1060 * Settings for sgtty based systems
1061 */
1062# ifndef USE_TERMIO
ed8f31c1 1063 termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
2c9c7136
PB
1064# endif /* USE_TERMIO */
1065
1066 /*
258d091a 1067 * Settings for UNICOS (and HPUX)
2c9c7136 1068 */
258d091a 1069# if defined(CRAY) || defined(__hpux)
2c9c7136
PB
1070 termbuf.c_oflag = OPOST|ONLCR|TAB3;
1071 termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
1072 termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
1073 termbuf.c_cflag = EXTB|HUPCL|CS8;
1074# endif
1075
1076 /*
1077 * Settings for all other termios/termio based
1078 * systems, other than 4.4BSD. In 4.4BSD the
1079 * kernel does the initial terminal setup.
1080 */
258d091a 1081# if defined(USE_TERMIO) && !(defined(CRAY) || defined(__hpux)) && (BSD <= 43)
2c9c7136
PB
1082# ifndef OXTABS
1083# define OXTABS 0
1084# endif
ea139302
PB
1085 termbuf.c_lflag |= ECHO;
1086 termbuf.c_oflag |= ONLCR|OXTABS;
1087 termbuf.c_iflag |= ICRNL;
1088 termbuf.c_iflag &= ~IXOFF;
2c9c7136 1089# endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */
4557054d
DB
1090 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
1091 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
1af3d848
DB
1092# ifdef LINEMODE
1093 if (waslm)
1094 tty_setlinemode(1);
1095# endif /* LINEMODE */
2c9c7136
PB
1096
1097 /*
1098 * Set the tty modes, and make this our controlling tty.
1099 */
ea139302 1100 set_termbuf();
2c9c7136
PB
1101 if (login_tty(t) == -1)
1102 fatalperror(net, "login_tty");
1103#endif /* !defined(CRAY) || !defined(NEWINIT) */
1104 if (net > 2)
1105 (void) close(net);
1106 if (pty > 2)
1107 (void) close(pty);
1108}
1109
1110#if !defined(CRAY) || !defined(NEWINIT)
1111#ifndef O_NOCTTY
1112#define O_NOCTTY 0
1113#endif
1114/*
1115 * Open the specified slave side of the pty,
1116 * making sure that we have a clean tty.
1117 */
1af3d848 1118 int
2c9c7136 1119cleanopen(line)
1af3d848 1120 char *line;
2c9c7136
PB
1121{
1122 register int t;
8832c633
DB
1123#if defined(_SC_CRAY_SECURE_SYS)
1124 struct secstat secbuf;
1125#endif /* _SC_CRAY_SECURE_SYS */
2c9c7136 1126
8832c633 1127#ifndef STREAMSPTY
2c9c7136
PB
1128 /*
1129 * Make sure that other people can't open the
1130 * slave side of the connection.
1131 */
ea139302
PB
1132 (void) chown(line, 0, 0);
1133 (void) chmod(line, 0600);
8832c633 1134#endif
2c9c7136
PB
1135
1136# if !defined(CRAY) && (BSD > 43)
1137 (void) revoke(line);
1138# endif
8832c633
DB
1139#if defined(_SC_CRAY_SECURE_SYS)
1140 if (secflag) {
1141 if (secstat(line, &secbuf) < 0)
1142 return(-1);
1143 if (setulvl(secbuf.st_slevel) < 0)
1144 return(-1);
1145 if (setucmp(secbuf.st_compart) < 0)
1146 return(-1);
1147 }
1148#endif /* _SC_CRAY_SECURE_SYS */
1149
2c9c7136 1150 t = open(line, O_RDWR|O_NOCTTY);
8832c633
DB
1151
1152#if defined(_SC_CRAY_SECURE_SYS)
1153 if (secflag) {
1154 if (setulvl(sysv.sy_minlvl) < 0)
1155 return(-1);
1156 if (setucmp(0) < 0)
1157 return(-1);
1158 }
1159#endif /* _SC_CRAY_SECURE_SYS */
1160
2c9c7136
PB
1161 if (t < 0)
1162 return(-1);
1163
1164 /*
1165 * Hangup anybody else using this ttyp, then reopen it for
1166 * ourselves.
1167 */
258d091a 1168# if !(defined(CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
2c9c7136
PB
1169 (void) signal(SIGHUP, SIG_IGN);
1170 vhangup();
1171 (void) signal(SIGHUP, SIG_DFL);
1172 t = open(line, O_RDWR|O_NOCTTY);
1173 if (t < 0)
1174 return(-1);
1175# endif
1176# if defined(CRAY) && defined(TCVHUP)
1177 {
1178 register int i;
1179 (void) signal(SIGHUP, SIG_IGN);
1180 (void) ioctl(t, TCVHUP, (char *)0);
1181 (void) signal(SIGHUP, SIG_DFL);
1182 setpgrp();
8832c633
DB
1183
1184#if defined(_SC_CRAY_SECURE_SYS)
1185 if (secflag) {
1186 if (secstat(line, &secbuf) < 0)
1187 return(-1);
1188 if (setulvl(secbuf.st_slevel) < 0)
1189 return(-1);
1190 if (setucmp(secbuf.st_compart) < 0)
1191 return(-1);
1192 }
1193#endif /* _SC_CRAY_SECURE_SYS */
1194
2c9c7136 1195 i = open(line, O_RDWR);
8832c633
DB
1196
1197#if defined(_SC_CRAY_SECURE_SYS)
1198 if (secflag) {
1199 if (setulvl(sysv.sy_minlvl) < 0)
1200 return(-1);
1201 if (setucmp(0) < 0)
1202 return(-1);
1203 }
1204#endif /* _SC_CRAY_SECURE_SYS */
1205
2c9c7136 1206 if (i < 0)
1af3d848 1207 return(-1);
2c9c7136
PB
1208 (void) close(t);
1209 t = i;
1210 }
1211# endif /* defined(CRAY) && defined(TCVHUP) */
ea139302
PB
1212 return(t);
1213}
2c9c7136
PB
1214#endif /* !defined(CRAY) || !defined(NEWINIT) */
1215
1216#if BSD <= 43
1af3d848 1217 int
2c9c7136 1218login_tty(t)
1af3d848 1219 int t;
2c9c7136 1220{
2c9c7136
PB
1221 if (setsid() < 0)
1222 fatalperror(net, "setsid()");
2c9c7136
PB
1223# ifdef TIOCSCTTY
1224 if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
1225 fatalperror(net, "ioctl(sctty)");
8832c633 1226# if defined(CRAY)
0163123f
DB
1227 /*
1228 * Close the hard fd to /dev/ttypXXX, and re-open through
1229 * the indirect /dev/tty interface.
1230 */
1231 close(t);
1232 if ((t = open("/dev/tty", O_RDWR)) < 0)
1233 fatalperror(net, "open(/dev/tty)");
1234# endif
2c9c7136
PB
1235# else
1236 close(open(line, O_RDWR));
1237# endif
0163123f
DB
1238 if (t != 0)
1239 (void) dup2(t, 0);
1240 if (t != 1)
1241 (void) dup2(t, 1);
1242 if (t != 2)
1243 (void) dup2(t, 2);
1244 if (t > 2)
1245 close(t);
1af3d848 1246 return(0);
2c9c7136
PB
1247}
1248#endif /* BSD <= 43 */
ea139302
PB
1249
1250#ifdef NEWINIT
1251char *gen_id = "fe";
1252#endif
1253
1254/*
2c9c7136 1255 * startslave(host)
ea139302 1256 *
2c9c7136 1257 * Given a hostname, do whatever
ea139302
PB
1258 * is necessary to startup the login process on the slave side of the pty.
1259 */
1260
1261/* ARGSUSED */
1af3d848
DB
1262 void
1263startslave(host, autologin, autoname)
1264 char *host;
1265 int autologin;
1266 char *autoname;
ea139302
PB
1267{
1268 register int i;
1269 long time();
1af3d848
DB
1270 char name[256];
1271#ifdef NEWINIT
1272 extern char *ptyip;
1273 struct init_request request;
1274 void nologinproc();
1275 register int n;
1276#endif /* NEWINIT */
1277
8832c633 1278#if defined(AUTHENTICATION)
1af3d848
DB
1279 if (!autoname || !autoname[0])
1280 autologin = 0;
1281
1282 if (autologin < auth_level) {
1283 fatal(net, "Authorization failed");
1284 exit(1);
1285 }
1286#endif
ea139302
PB
1287
1288#ifndef NEWINIT
258d091a 1289# ifdef PARENT_DOES_UTMP
ea139302 1290 utmp_sig_init();
258d091a 1291# endif /* PARENT_DOES_UTMP */
ea139302
PB
1292
1293 if ((i = fork()) < 0)
1294 fatalperror(net, "fork");
1295 if (i) {
258d091a 1296# ifdef PARENT_DOES_UTMP
ea139302
PB
1297 /*
1298 * Cray parent will create utmp entry for child and send
1299 * signal to child to tell when done. Child waits for signal
1300 * before doing anything important.
1301 */
1302 register int pid = i;
1af3d848 1303 void sigjob P((int));
ea139302
PB
1304
1305 setpgrp();
4a8a7128 1306 utmp_sig_reset(); /* reset handler to default */
ea139302
PB
1307 /*
1308 * Create utmp entry for child
1309 */
1310 (void) time(&wtmp.ut_time);
1311 wtmp.ut_type = LOGIN_PROCESS;
1312 wtmp.ut_pid = pid;
1313 SCPYN(wtmp.ut_user, "LOGIN");
1314 SCPYN(wtmp.ut_host, host);
1315 SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1);
258d091a 1316#ifndef __hpux
ea139302 1317 SCPYN(wtmp.ut_id, wtmp.ut_line+3);
258d091a
DB
1318#else
1319 SCPYN(wtmp.ut_id, wtmp.ut_line+7);
1320#endif
ea139302
PB
1321 pututline(&wtmp);
1322 endutent();
1323 if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
1324 (void) write(i, (char *)&wtmp, sizeof(struct utmp));
1325 (void) close(i);
1326 }
258d091a 1327#ifdef CRAY
1af3d848 1328 (void) signal(WJSIGNAL, sigjob);
258d091a 1329#endif
ea139302 1330 utmp_sig_notify(pid);
258d091a 1331# endif /* PARENT_DOES_UTMP */
ea139302 1332 } else {
2c9c7136 1333 getptyslave();
1af3d848 1334 start_login(host, autologin, autoname);
ea139302
PB
1335 /*NOTREACHED*/
1336 }
1337#else /* NEWINIT */
1338
ea139302
PB
1339 /*
1340 * Init will start up login process if we ask nicely. We only wait
1341 * for it to start up and begin normal telnet operation.
1342 */
1343 if ((i = open(INIT_FIFO, O_WRONLY)) < 0) {
1344 char tbuf[128];
1345 (void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO);
1346 fatalperror(net, tbuf);
1347 }
1348 memset((char *)&request, 0, sizeof(request));
1349 request.magic = INIT_MAGIC;
1350 SCPYN(request.gen_id, gen_id);
1351 SCPYN(request.tty_id, &line[8]);
1352 SCPYN(request.host, host);
1af3d848 1353 SCPYN(request.term_type, terminaltype ? terminaltype : "network");
4a8a7128 1354#if !defined(UNICOS5)
ed8f31c1
PB
1355 request.signal = SIGCLD;
1356 request.pid = getpid();
1357#endif
4a8a7128
PB
1358#ifdef BFTPDAEMON
1359 /*
1360 * Are we working as the bftp daemon?
1361 */
1362 if (bftpd) {
1363 SCPYN(request.exec_name, BFTPPATH);
1364 }
1365#endif /* BFTPDAEMON */
ea139302
PB
1366 if (write(i, (char *)&request, sizeof(request)) < 0) {
1367 char tbuf[128];
1368 (void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO);
1369 fatalperror(net, tbuf);
1370 }
1371 (void) close(i);
1372 (void) signal(SIGALRM, nologinproc);
1373 for (i = 0; ; i++) {
ed8f31c1 1374 char tbuf[128];
ea139302
PB
1375 alarm(15);
1376 n = read(pty, ptyip, BUFSIZ);
1377 if (i == 3 || n >= 0 || !gotalarm)
1378 break;
1379 gotalarm = 0;
ed8f31c1
PB
1380 sprintf(tbuf, "telnetd: waiting for /etc/init to start login process on %s\r\n", line);
1381 (void) write(net, tbuf, strlen(tbuf));
ea139302
PB
1382 }
1383 if (n < 0 && gotalarm)
1384 fatal(net, "/etc/init didn't start login process");
1385 pcc += n;
1386 alarm(0);
1387 (void) signal(SIGALRM, SIG_DFL);
1388
ea139302
PB
1389 return;
1390#endif /* NEWINIT */
1391}
1392
ea139302 1393char *envinit[3];
4a8a7128
PB
1394extern char **environ;
1395
1af3d848 1396 void
4a8a7128
PB
1397init_env()
1398{
1399 extern char *getenv();
1400 char **envp;
1401
1402 envp = envinit;
1403 if (*envp = getenv("TZ"))
1404 *envp++ -= 3;
258d091a 1405#if defined(CRAY) || defined(__hpux)
4a8a7128
PB
1406 else
1407 *envp++ = "TZ=GMT0";
1408#endif
1409 *envp = 0;
1410 environ = envinit;
1411}
1412
4a8a7128 1413#ifndef NEWINIT
ea139302
PB
1414
1415/*
2c9c7136 1416 * start_login(host)
ea139302
PB
1417 *
1418 * Assuming that we are now running as a child processes, this
1419 * function will turn us into the login process.
1420 */
1421
1af3d848
DB
1422 void
1423start_login(host, autologin, name)
1424 char *host;
1425 int autologin;
1426 char *name;
ea139302 1427{
4a8a7128
PB
1428 register char *cp;
1429 register char **argv;
1430 char **addarg();
8832c633
DB
1431#ifdef UTMPX
1432 register int pid = getpid();
1433 struct utmpx utmpx;
1434#endif
1435#ifdef __svr4__
1436 char *term;
1437 char termbuf[64];
1438#endif
1439
1440#ifdef UTMPX
1441 /*
1442 * Create utmp entry for child
1443 */
1444
1445 bzero(&utmpx, sizeof(utmpx));
1446 SCPYN(utmpx.ut_user, ".telnet");
1447 SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1);
1448 utmpx.ut_pid = pid;
1449 utmpx.ut_id[0] = 't';
1450 utmpx.ut_id[1] = 'n';
1451 utmpx.ut_id[2] = SC_WILDC;
1452 utmpx.ut_id[3] = SC_WILDC;
1453 utmpx.ut_type = LOGIN_PROCESS;
1454 (void) time(&utmpx.ut_tv.tv_sec);
1455 if (makeutx(&utmpx) == NULL)
1456 fatal(net, "makeutx failed");
1457#endif
ea139302 1458
ea139302
PB
1459 /*
1460 * -h : pass on name of host.
1461 * WARNING: -h is accepted by login if and only if
1462 * getuid() == 0.
1463 * -p : don't clobber the environment (so terminal type stays set).
1af3d848
DB
1464 *
1465 * -f : force this login, he has already been authenticated
ea139302 1466 */
4a8a7128 1467 argv = addarg(0, "login");
258d091a 1468#if !defined(NO_LOGIN_H)
4a8a7128
PB
1469 argv = addarg(argv, "-h");
1470 argv = addarg(argv, host);
258d091a 1471#endif
8832c633
DB
1472#ifdef __svr4__
1473 /*
1474 * SVR4 version of -h takes TERM= as second arg, or -
1475 */
1476 term = getenv("TERM");
1477 if (term == NULL || term[0] == 0) {
1478 term = "-";
1479 } else {
1480 strcpy(termbuf, "TERM=");
1481 strncat(termbuf, term, sizeof(termbuf) - 6);
1482 term = termbuf;
1483 }
1484 argv = addarg(argv, term);
1485#endif
1af3d848 1486#if !defined(NO_LOGIN_P)
4a8a7128
PB
1487 argv = addarg(argv, "-p");
1488#endif
1489#ifdef BFTPDAEMON
1490 /*
1491 * Are we working as the bftp daemon? If so, then ask login
1492 * to start bftp instead of shell.
1493 */
1494 if (bftpd) {
1495 argv = addarg(argv, "-e");
1496 argv = addarg(argv, BFTPPATH);
1497 } else
1af3d848
DB
1498#endif
1499#if defined (SecurID)
1500 /*
1501 * don't worry about the -f that might get sent.
1502 * A -s is supposed to override it anyhow.
1503 */
1504 if (require_SecurID)
1505 argv = addarg(argv, "-s");
1506#endif
8832c633 1507#if defined (AUTHENTICATION)
1af3d848
DB
1508 if (auth_level >= 0 && autologin == AUTH_VALID) {
1509# if !defined(NO_LOGIN_F)
1510 argv = addarg(argv, "-f");
1511# endif
1512 argv = addarg(argv, name);
1513 } else
4a8a7128
PB
1514#endif
1515 if (getenv("USER")) {
1516 argv = addarg(argv, getenv("USER"));
258d091a 1517#if (defined(CRAY) || defined(__hpux)) && defined(NO_LOGIN_P)
1af3d848
DB
1518 {
1519 register char **cpp;
1520 for (cpp = environ; *cpp; cpp++)
1521 argv = addarg(argv, *cpp);
1522 }
ea139302 1523#endif
8832c633
DB
1524 /*
1525 * Assume that login will set the USER variable
1526 * correctly. For SysV systems, this means that
1527 * USER will no longer be set, just LOGNAME by
1528 * login. (The problem is that if the auto-login
1529 * fails, and the user then specifies a different
1530 * account name, he can get logged in with both
1531 * LOGNAME and USER in his environment, but the
1532 * USER value will be wrong.
1533 */
1534 unsetenv("USER");
1af3d848
DB
1535 }
1536 closelog();
4a8a7128
PB
1537 execv(_PATH_LOGIN, argv);
1538
ea139302
PB
1539 syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
1540 fatalperror(net, _PATH_LOGIN);
1541 /*NOTREACHED*/
1542}
4a8a7128 1543
1af3d848 1544 char **
4a8a7128 1545addarg(argv, val)
1af3d848
DB
1546 register char **argv;
1547 register char *val;
4a8a7128
PB
1548{
1549 register char **cpp;
4a8a7128
PB
1550
1551 if (argv == NULL) {
1552 /*
1553 * 10 entries, a leading length, and a null
1554 */
1555 argv = (char **)malloc(sizeof(*argv) * 12);
1556 if (argv == NULL)
1557 return(NULL);
1558 *argv++ = (char *)10;
1559 *argv = (char *)0;
1560 }
1561 for (cpp = argv; *cpp; cpp++)
1562 ;
1563 if (cpp == &argv[(int)argv[-1]]) {
1564 --argv;
1565 *argv = (char *)((int)(*argv) + 10);
1566 argv = (char **)realloc(argv, (int)(*argv) + 2);
1567 if (argv == NULL)
1568 return(NULL);
1569 argv++;
1570 cpp = &argv[(int)argv[-1] - 10];
1571 }
1572 *cpp++ = val;
1573 *cpp = 0;
1574 return(argv);
1575}
1af3d848 1576#endif /* NEWINIT */
ea139302
PB
1577
1578/*
1579 * cleanup()
1580 *
1581 * This is the routine to call when we are all through, to
1582 * clean up anything that needs to be cleaned up.
1583 */
1af3d848
DB
1584 /* ARGSUSED */
1585 void
1586cleanup(sig)
1587 int sig;
ea139302 1588{
258d091a 1589#ifndef PARENT_DOES_UTMP
2c9c7136 1590# if (BSD > 43) || defined(convex)
ea139302
PB
1591 char *p;
1592
1593 p = line + sizeof("/dev/") - 1;
1594 if (logout(p))
1595 logwtmp(p, "", "");
1596 (void)chmod(line, 0666);
1597 (void)chown(line, 0, 0);
1598 *p = 'p';
1599 (void)chmod(line, 0666);
1600 (void)chown(line, 0, 0);
1af3d848
DB
1601 (void) shutdown(net, 2);
1602 exit(1);
ea139302 1603# else
1af3d848
DB
1604 void rmut();
1605
ea139302
PB
1606 rmut();
1607 vhangup(); /* XXX */
ea139302 1608 (void) shutdown(net, 2);
1af3d848
DB
1609 exit(1);
1610# endif
258d091a 1611#else /* PARENT_DOES_UTMP */
1af3d848 1612# ifdef NEWINIT
ea139302 1613 (void) shutdown(net, 2);
1af3d848 1614 exit(1);
ea139302 1615# else /* NEWINIT */
258d091a 1616# ifdef CRAY
1af3d848
DB
1617 static int incleanup = 0;
1618 register int t;
1619
1620 /*
1621 * 1: Pick up the zombie, if we are being called
1622 * as the signal handler.
1623 * 2: If we are a nested cleanup(), return.
1624 * 3: Try to clean up TMPDIR.
1625 * 4: Fill in utmp with shutdown of process.
1626 * 5: Close down the network and pty connections.
1627 * 6: Finish up the TMPDIR cleanup, if needed.
1628 */
1629 if (sig == SIGCHLD)
1630 while (waitpid(-1, 0, WNOHANG) > 0)
1631 ; /* VOID */
1632 t = sigblock(sigmask(SIGCHLD));
1633 if (incleanup) {
1634 sigsetmask(t);
1635 return;
1636 }
1637 incleanup = 1;
1638 sigsetmask(t);
258d091a
DB
1639 if (secflag) {
1640 /*
1641 * We need to set ourselves back to a null
1642 * label to clean up.
1643 */
1644
1645 setulvl(sysv.sy_minlvl);
1646 setucmp((long)0);
1647 }
1af3d848
DB
1648
1649 t = cleantmp(&wtmp);
1650 setutent(); /* just to make sure */
258d091a 1651# endif /* CRAY */
1af3d848
DB
1652 rmut(line);
1653 close(pty);
ea139302 1654 (void) shutdown(net, 2);
258d091a 1655# ifdef CRAY
1af3d848
DB
1656 if (t == 0)
1657 cleantmp(&wtmp);
258d091a 1658# endif /* CRAY */
1af3d848 1659 exit(1);
ea139302 1660# endif /* NEWINT */
258d091a 1661#endif /* PARENT_DOES_UTMP */
ea139302
PB
1662}
1663
258d091a 1664#if defined(PARENT_DOES_UTMP) && !defined(NEWINIT)
ea139302
PB
1665/*
1666 * _utmp_sig_rcv
1667 * utmp_sig_init
1668 * utmp_sig_wait
1669 * These three functions are used to coordinate the handling of
1670 * the utmp file between the server and the soon-to-be-login shell.
1671 * The server actually creates the utmp structure, the child calls
1672 * utmp_sig_wait(), until the server calls utmp_sig_notify() and
1673 * signals the future-login shell to proceed.
1674 */
1675static int caught=0; /* NZ when signal intercepted */
1676static void (*func)(); /* address of previous handler */
1677
1af3d848 1678 void
ea139302 1679_utmp_sig_rcv(sig)
1af3d848 1680 int sig;
ea139302
PB
1681{
1682 caught = 1;
1683 (void) signal(SIGUSR1, func);
1684}
1685
1af3d848 1686 void
ea139302
PB
1687utmp_sig_init()
1688{
1689 /*
1690 * register signal handler for UTMP creation
1691 */
1692 if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1693 fatalperror(net, "telnetd/signal");
1694}
1695
1af3d848 1696 void
4a8a7128
PB
1697utmp_sig_reset()
1698{
1699 (void) signal(SIGUSR1, func); /* reset handler to default */
1700}
1701
258d091a
DB
1702# ifdef __hpux
1703# define sigoff() /* do nothing */
1704# define sigon() /* do nothing */
1705# endif
1706
1af3d848 1707 void
ea139302
PB
1708utmp_sig_wait()
1709{
1710 /*
1711 * Wait for parent to write our utmp entry.
1712 */
1713 sigoff();
1714 while (caught == 0) {
1715 pause(); /* wait until we get a signal (sigon) */
1716 sigoff(); /* turn off signals while we check caught */
1717 }
1718 sigon(); /* turn on signals again */
1719}
1720
1af3d848 1721 void
ea139302
PB
1722utmp_sig_notify(pid)
1723{
1724 kill(pid, SIGUSR1);
1725}
1af3d848 1726
258d091a 1727# ifdef CRAY
1af3d848
DB
1728static int gotsigjob = 0;
1729
1730 /*ARGSUSED*/
1731 void
1732sigjob(sig)
1733 int sig;
1734{
1735 register int jid;
1736 register struct jobtemp *jp;
1737
1738 while ((jid = waitjob(NULL)) != -1) {
1739 if (jid == 0) {
1740 return;
1741 }
1742 gotsigjob++;
1743 jobend(jid, NULL, NULL);
1744 }
1745}
1746
1747/*
1748 * Clean up the TMPDIR that login created.
1749 * The first time this is called we pick up the info
1750 * from the utmp. If the job has already gone away,
1751 * then we'll clean up and be done. If not, then
1752 * when this is called the second time it will wait
1753 * for the signal that the job is done.
1754 */
1755 int
1756cleantmp(wtp)
1757 register struct utmp *wtp;
1758{
1759 struct utmp *utp;
1760 static int first = 1;
1761 register int mask, omask, ret;
1762 extern struct utmp *getutid P((struct utmp *));
1763
1764 mask = sigmask(WJSIGNAL);
1765
1766 if (first == 0) {
1767 omask = sigblock(mask);
1768 while (gotsigjob == 0)
1769 sigpause(omask);
1770 return(1);
1771 }
1772 first = 0;
1773 setutent(); /* just to make sure */
1774
1775 utp = getutid(wtp);
1776 if (utp == 0) {
1777 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1778 return(-1);
1779 }
1780 /*
1781 * Nothing to clean up if the user shell was never started.
1782 */
1783 if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
1784 return(1);
1785
1786 /*
1787 * Block the WJSIGNAL while we are in jobend().
1788 */
1789 omask = sigblock(mask);
1790 ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
1791 sigsetmask(omask);
1792 return(ret);
1793}
1794
1795 int
1796jobend(jid, path, user)
1797 register int jid;
1798 register char *path;
1799 register char *user;
1800{
1801 static int saved_jid = 0;
1802 static char saved_path[sizeof(wtmp.ut_tpath)+1];
1803 static char saved_user[sizeof(wtmp.ut_user)+1];
1804
1805 if (path) {
1806 strncpy(saved_path, path, sizeof(wtmp.ut_tpath));
1807 strncpy(saved_user, user, sizeof(wtmp.ut_user));
1808 saved_path[sizeof(saved_path)] = '\0';
1809 saved_user[sizeof(saved_user)] = '\0';
1810 }
1811 if (saved_jid == 0) {
1812 saved_jid = jid;
1813 return(0);
1814 }
1815 cleantmpdir(jid, saved_path, saved_user);
1816 return(1);
1817}
1818
1819/*
1820 * Fork a child process to clean up the TMPDIR
1821 */
1822cleantmpdir(jid, tpath, user)
1823 register int jid;
1824 register char *tpath;
1825 register char *user;
1826{
1827 switch(fork()) {
1828 case -1:
1829 syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
1830 tpath);
1831 break;
1832 case 0:
1833 execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0);
1834 syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1835 tpath, CLEANTMPCMD);
1836 exit(1);
1837 default:
1838 /*
1839 * Forget about child. We will exit, and
1840 * /etc/init will pick it up.
1841 */
1842 break;
1843 }
1844}
258d091a
DB
1845# endif /* CRAY */
1846#endif /* defined(PARENT_DOES_UTMP) && !defined(NEWINIT) */
ea139302
PB
1847
1848/*
1849 * rmut()
1850 *
1851 * This is the function called by cleanup() to
1852 * remove the utmp entry for this person.
1853 */
1854
8832c633
DB
1855#ifdef UTMPX
1856rmut()
1857{
1858 register f;
1859 int found = 0;
1860 struct utmp *u, *utmp;
1861 int nutmp;
1862 struct stat statbf;
1863
1864 struct utmpx *utxp, utmpx;
1865
1866 /*
1867 * This updates the utmpx and utmp entries and make a wtmp/x entry
1868 */
1869
1870 SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1);
1871 utxp = getutxline(&utmpx);
1872 if (utxp) {
1873 utxp->ut_type = DEAD_PROCESS;
1874 utxp->ut_exit.e_termination = 0;
1875 utxp->ut_exit.e_exit = 0;
1876 (void) time(&utmpx.ut_tv.tv_sec);
1877 utmpx.ut_tv.tv_usec = 0;
1878 modutx(utxp);
1879 }
1880 endutxent();
1881} /* end of rmut */
1882#endif
1883
258d091a 1884#if !defined(UTMPX) && !(defined(CRAY) || defined(__hpux)) && BSD <= 43
1af3d848 1885 void
ea139302
PB
1886rmut()
1887{
1888 register f;
1889 int found = 0;
1890 struct utmp *u, *utmp;
1891 int nutmp;
1892 struct stat statbf;
ea139302
PB
1893
1894 f = open(utmpf, O_RDWR);
1895 if (f >= 0) {
1896 (void) fstat(f, &statbf);
1897 utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
1898 if (!utmp)
1899 syslog(LOG_ERR, "utmp malloc failed");
1900 if (statbf.st_size && utmp) {
1901 nutmp = read(f, (char *)utmp, (int)statbf.st_size);
1902 nutmp /= sizeof(struct utmp);
1903
1904 for (u = utmp ; u < &utmp[nutmp] ; u++) {
1905 if (SCMPN(u->ut_line, line+5) ||
1906 u->ut_name[0]==0)
1907 continue;
1908 (void) lseek(f, ((long)u)-((long)utmp), L_SET);
1909 SCPYN(u->ut_name, "");
1910 SCPYN(u->ut_host, "");
1911 (void) time(&u->ut_time);
1912 (void) write(f, (char *)u, sizeof(wtmp));
1913 found++;
1914 }
1915 }
1916 (void) close(f);
1917 }
1918 if (found) {
1919 f = open(wtmpf, O_WRONLY|O_APPEND);
1920 if (f >= 0) {
1921 SCPYN(wtmp.ut_line, line+5);
1922 SCPYN(wtmp.ut_name, "");
1923 SCPYN(wtmp.ut_host, "");
1924 (void) time(&wtmp.ut_time);
1925 (void) write(f, (char *)&wtmp, sizeof(wtmp));
1926 (void) close(f);
1927 }
1928 }
1929 (void) chmod(line, 0666);
1930 (void) chown(line, 0, 0);
1931 line[strlen("/dev/")] = 'p';
1932 (void) chmod(line, 0666);
1933 (void) chown(line, 0, 0);
1934} /* end of rmut */
1935#endif /* CRAY */
258d091a
DB
1936
1937#ifdef __hpux
1938rmut (line)
1939char *line;
1940{
1941 struct utmp utmp;
1942 struct utmp *utptr;
1943 int fd; /* for /etc/wtmp */
1944
1945 utmp.ut_type = USER_PROCESS;
1946 (void) strncpy(utmp.ut_id, line+12, sizeof(utmp.ut_id));
1947 (void) setutent();
1948 utptr = getutid(&utmp);
1949 /* write it out only if it exists */
1950 if (utptr) {
1951 utptr->ut_type = DEAD_PROCESS;
1952 utptr->ut_time = time((long *) 0);
1953 (void) pututline(utptr);
1954 /* set wtmp entry if wtmp file exists */
1955 if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
1956 (void) write(fd, utptr, sizeof(utmp));
1957 (void) close(fd);
1958 }
1959 }
1960 (void) endutent();
1961
1962 (void) chmod(line, 0666);
1963 (void) chown(line, 0, 0);
1964 line[14] = line[13];
1965 line[13] = line[12];
1966 line[8] = 'm';
1967 line[9] = '/';
1968 line[10] = 'p';
1969 line[11] = 't';
1970 line[12] = 'y';
1971 (void) chmod(line, 0666);
1972 (void) chown(line, 0, 0);
1973}
1974#endif