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