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