Initial import from FreeBSD RELENG_4:
[dragonfly.git] / libexec / telnetd / sys_term.c
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 #include <sys/cdefs.h>
35
36 __FBSDID("$FreeBSD: src/libexec/telnetd/sys_term.c,v 1.24.2.8 2002/06/17 02:48:06 jmallett Exp $");
37
38 #ifndef lint
39 static const char sccsid[] = "@(#)sys_term.c    8.4+1 (Berkeley) 5/30/95";
40 #endif
41
42 #include <sys/types.h>
43 #include <sys/tty.h>
44 #include <libutil.h>
45 #include <stdlib.h>
46 #include <utmp.h>
47
48 #include "telnetd.h"
49 #include "pathnames.h"
50
51
52 int cleanopen(char *);
53 void scrub_env(void);
54
55 struct  utmp wtmp;
56
57 #ifdef _PATH_WTMP
58 char    wtmpf[] = _PATH_WTMP;
59 #else
60 char    wtmpf[] = "/var/log/wtmp";
61 #endif
62 #ifdef _PATH_UTMP
63 char    utmpf[] = _PATH_UTMP;
64 #else
65 char    utmpf[] = "/var/run/utmp";
66 #endif
67
68 char    *envinit[3];
69 extern char **environ;
70
71 #define SCPYN(a, b)     (void) strncpy(a, b, sizeof(a))
72 #define SCMPN(a, b)     strncmp(a, b, sizeof(a))
73
74 #ifdef  t_erase
75 #undef  t_erase
76 #undef  t_kill
77 #undef  t_intrc
78 #undef  t_quitc
79 #undef  t_startc
80 #undef  t_stopc
81 #undef  t_eofc
82 #undef  t_brkc
83 #undef  t_suspc
84 #undef  t_dsuspc
85 #undef  t_rprntc
86 #undef  t_flushc
87 #undef  t_werasc
88 #undef  t_lnextc
89 #endif
90
91 #ifndef USE_TERMIO
92 struct termbuf {
93         struct sgttyb sg;
94         struct tchars tc;
95         struct ltchars ltc;
96         int state;
97         int lflags;
98 } termbuf, termbuf2;
99 # define        cfsetospeed(tp, val)    (tp)->sg.sg_ospeed = (val)
100 # define        cfsetispeed(tp, val)    (tp)->sg.sg_ispeed = (val)
101 # define        cfgetospeed(tp)         (tp)->sg.sg_ospeed
102 # define        cfgetispeed(tp)         (tp)->sg.sg_ispeed
103 #else   /* USE_TERMIO */
104 # ifndef        TCSANOW
105 #  ifdef TCSETS
106 #   define      TCSANOW         TCSETS
107 #   define      TCSADRAIN       TCSETSW
108 #   define      tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
109 #  else
110 #   ifdef TCSETA
111 #    define     TCSANOW         TCSETA
112 #    define     TCSADRAIN       TCSETAW
113 #    define     tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
114 #   else
115 #    define     TCSANOW         TIOCSETA
116 #    define     TCSADRAIN       TIOCSETAW
117 #    define     tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
118 #   endif
119 #  endif
120 #  define       tcsetattr(f, a, t)      ioctl(f, a, t)
121 #  define       cfsetospeed(tp, val)    (tp)->c_cflag &= ~CBAUD; \
122                                         (tp)->c_cflag |= (val)
123 #  define       cfgetospeed(tp)         ((tp)->c_cflag & CBAUD)
124 #  ifdef CIBAUD
125 #   define      cfsetispeed(tp, val)    (tp)->c_cflag &= ~CIBAUD; \
126                                         (tp)->c_cflag |= ((val)<<IBSHIFT)
127 #   define      cfgetispeed(tp)         (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
128 #  else
129 #   define      cfsetispeed(tp, val)    (tp)->c_cflag &= ~CBAUD; \
130                                         (tp)->c_cflag |= (val)
131 #   define      cfgetispeed(tp)         ((tp)->c_cflag & CBAUD)
132 #  endif
133 # endif /* TCSANOW */
134 struct termios termbuf, termbuf2;       /* pty control structure */
135 #endif  /* USE_TERMIO */
136
137 #include <sys/types.h>
138 #include <libutil.h>
139
140 int cleanopen(char *);
141 void scrub_env(void);
142 static char **addarg(char **, const char *);
143
144 /*
145  * init_termbuf()
146  * copy_termbuf(cp)
147  * set_termbuf()
148  *
149  * These three routines are used to get and set the "termbuf" structure
150  * to and from the kernel.  init_termbuf() gets the current settings.
151  * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
152  * set_termbuf() writes the structure into the kernel.
153  */
154
155 void
156 init_termbuf(void)
157 {
158 #ifndef USE_TERMIO
159         (void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg);
160         (void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc);
161         (void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc);
162 # ifdef TIOCGSTATE
163         (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
164 # endif
165 #else
166         (void) tcgetattr(pty, &termbuf);
167 #endif
168         termbuf2 = termbuf;
169 }
170
171 #if     defined(LINEMODE) && defined(TIOCPKT_IOCTL)
172 void
173 copy_termbuf(char *cp, size_t len)
174 {
175         if (len > sizeof(termbuf))
176                 len = sizeof(termbuf);
177         memmove((char *)&termbuf, cp, len);
178         termbuf2 = termbuf;
179 }
180 #endif  /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
181
182 void
183 set_termbuf(void)
184 {
185         /*
186          * Only make the necessary changes.
187          */
188 #ifndef USE_TERMIO
189         if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg,
190                                                         sizeof(termbuf.sg)))
191                 (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg);
192         if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc,
193                                                         sizeof(termbuf.tc)))
194                 (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
195         if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
196                                                         sizeof(termbuf.ltc)))
197                 (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
198         if (termbuf.lflags != termbuf2.lflags)
199                 (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
200 #else   /* USE_TERMIO */
201         if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
202                 (void) tcsetattr(pty, TCSANOW, &termbuf);
203 #endif  /* USE_TERMIO */
204 }
205
206
207 /*
208  * spcset(func, valp, valpp)
209  *
210  * This function takes various special characters (func), and
211  * sets *valp to the current value of that character, and
212  * *valpp to point to where in the "termbuf" structure that
213  * value is kept.
214  *
215  * It returns the SLC_ level of support for this function.
216  */
217
218 #ifndef USE_TERMIO
219 int
220 spcset(int func, cc_t *valp, cc_t **valpp)
221 {
222         switch(func) {
223         case SLC_EOF:
224                 *valp = termbuf.tc.t_eofc;
225                 *valpp = (cc_t *)&termbuf.tc.t_eofc;
226                 return(SLC_VARIABLE);
227         case SLC_EC:
228                 *valp = termbuf.sg.sg_erase;
229                 *valpp = (cc_t *)&termbuf.sg.sg_erase;
230                 return(SLC_VARIABLE);
231         case SLC_EL:
232                 *valp = termbuf.sg.sg_kill;
233                 *valpp = (cc_t *)&termbuf.sg.sg_kill;
234                 return(SLC_VARIABLE);
235         case SLC_IP:
236                 *valp = termbuf.tc.t_intrc;
237                 *valpp = (cc_t *)&termbuf.tc.t_intrc;
238                 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
239         case SLC_ABORT:
240                 *valp = termbuf.tc.t_quitc;
241                 *valpp = (cc_t *)&termbuf.tc.t_quitc;
242                 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
243         case SLC_XON:
244                 *valp = termbuf.tc.t_startc;
245                 *valpp = (cc_t *)&termbuf.tc.t_startc;
246                 return(SLC_VARIABLE);
247         case SLC_XOFF:
248                 *valp = termbuf.tc.t_stopc;
249                 *valpp = (cc_t *)&termbuf.tc.t_stopc;
250                 return(SLC_VARIABLE);
251         case SLC_AO:
252                 *valp = termbuf.ltc.t_flushc;
253                 *valpp = (cc_t *)&termbuf.ltc.t_flushc;
254                 return(SLC_VARIABLE);
255         case SLC_SUSP:
256                 *valp = termbuf.ltc.t_suspc;
257                 *valpp = (cc_t *)&termbuf.ltc.t_suspc;
258                 return(SLC_VARIABLE);
259         case SLC_EW:
260                 *valp = termbuf.ltc.t_werasc;
261                 *valpp = (cc_t *)&termbuf.ltc.t_werasc;
262                 return(SLC_VARIABLE);
263         case SLC_RP:
264                 *valp = termbuf.ltc.t_rprntc;
265                 *valpp = (cc_t *)&termbuf.ltc.t_rprntc;
266                 return(SLC_VARIABLE);
267         case SLC_LNEXT:
268                 *valp = termbuf.ltc.t_lnextc;
269                 *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
270                 return(SLC_VARIABLE);
271         case SLC_FORW1:
272                 *valp = termbuf.tc.t_brkc;
273                 *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
274                 return(SLC_VARIABLE);
275         case SLC_BRK:
276         case SLC_SYNCH:
277         case SLC_AYT:
278         case SLC_EOR:
279                 *valp = (cc_t)0;
280                 *valpp = (cc_t *)0;
281                 return(SLC_DEFAULT);
282         default:
283                 *valp = (cc_t)0;
284                 *valpp = (cc_t *)0;
285                 return(SLC_NOSUPPORT);
286         }
287 }
288
289 #else   /* USE_TERMIO */
290
291
292 #define setval(a, b)    *valp = termbuf.c_cc[a]; \
293                         *valpp = &termbuf.c_cc[a]; \
294                         return(b);
295 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
296
297 int
298 spcset(int func, cc_t *valp, cc_t **valpp)
299 {
300         switch(func) {
301         case SLC_EOF:
302                 setval(VEOF, SLC_VARIABLE);
303         case SLC_EC:
304                 setval(VERASE, SLC_VARIABLE);
305         case SLC_EL:
306                 setval(VKILL, SLC_VARIABLE);
307         case SLC_IP:
308                 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
309         case SLC_ABORT:
310                 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
311         case SLC_XON:
312 #ifdef  VSTART
313                 setval(VSTART, SLC_VARIABLE);
314 #else
315                 defval(0x13);
316 #endif
317         case SLC_XOFF:
318 #ifdef  VSTOP
319                 setval(VSTOP, SLC_VARIABLE);
320 #else
321                 defval(0x11);
322 #endif
323         case SLC_EW:
324 #ifdef  VWERASE
325                 setval(VWERASE, SLC_VARIABLE);
326 #else
327                 defval(0);
328 #endif
329         case SLC_RP:
330 #ifdef  VREPRINT
331                 setval(VREPRINT, SLC_VARIABLE);
332 #else
333                 defval(0);
334 #endif
335         case SLC_LNEXT:
336 #ifdef  VLNEXT
337                 setval(VLNEXT, SLC_VARIABLE);
338 #else
339                 defval(0);
340 #endif
341         case SLC_AO:
342 #if     !defined(VDISCARD) && defined(VFLUSHO)
343 # define VDISCARD VFLUSHO
344 #endif
345 #ifdef  VDISCARD
346                 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
347 #else
348                 defval(0);
349 #endif
350         case SLC_SUSP:
351 #ifdef  VSUSP
352                 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
353 #else
354                 defval(0);
355 #endif
356 #ifdef  VEOL
357         case SLC_FORW1:
358                 setval(VEOL, SLC_VARIABLE);
359 #endif
360 #ifdef  VEOL2
361         case SLC_FORW2:
362                 setval(VEOL2, SLC_VARIABLE);
363 #endif
364         case SLC_AYT:
365 #ifdef  VSTATUS
366                 setval(VSTATUS, SLC_VARIABLE);
367 #else
368                 defval(0);
369 #endif
370
371         case SLC_BRK:
372         case SLC_SYNCH:
373         case SLC_EOR:
374                 defval(0);
375
376         default:
377                 *valp = 0;
378                 *valpp = 0;
379                 return(SLC_NOSUPPORT);
380         }
381 }
382 #endif  /* USE_TERMIO */
383
384 /*
385  * getpty()
386  *
387  * Allocate a pty.  As a side effect, the external character
388  * array "line" contains the name of the slave side.
389  *
390  * Returns the file descriptor of the opened pty.
391  */
392 char alpha[] = "0123456789abcdefghijklmnopqrstuv";
393 char line[16];
394
395 int
396 getpty(int *ptynum __unused)
397 {
398         int p;
399         const char *cp;
400         char *p1, *p2;
401         int i;
402
403         (void) strcpy(line, _PATH_DEV);
404         (void) strcat(line, "ptyXX");
405         p1 = &line[8];
406         p2 = &line[9];
407
408         for (cp = "pqrsPQRS"; *cp; cp++) {
409                 struct stat stb;
410
411                 *p1 = *cp;
412                 *p2 = '0';
413                 /*
414                  * This stat() check is just to keep us from
415                  * looping through all 256 combinations if there
416                  * aren't that many ptys available.
417                  */
418                 if (stat(line, &stb) < 0)
419                         break;
420                 for (i = 0; i < 32; i++) {
421                         *p2 = alpha[i];
422                         p = open(line, 2);
423                         if (p > 0) {
424                                 line[5] = 't';
425                                 chown(line, 0, 0);
426                                 chmod(line, 0600);
427                                         return(p);
428                         }
429                 }
430         }
431         return(-1);
432 }
433
434 #ifdef  LINEMODE
435 /*
436  * tty_flowmode()       Find out if flow control is enabled or disabled.
437  * tty_linemode()       Find out if linemode (external processing) is enabled.
438  * tty_setlinemod(on)   Turn on/off linemode.
439  * tty_isecho()         Find out if echoing is turned on.
440  * tty_setecho(on)      Enable/disable character echoing.
441  * tty_israw()          Find out if terminal is in RAW mode.
442  * tty_binaryin(on)     Turn on/off BINARY on input.
443  * tty_binaryout(on)    Turn on/off BINARY on output.
444  * tty_isediting()      Find out if line editing is enabled.
445  * tty_istrapsig()      Find out if signal trapping is enabled.
446  * tty_setedit(on)      Turn on/off line editing.
447  * tty_setsig(on)       Turn on/off signal trapping.
448  * tty_issofttab()      Find out if tab expansion is enabled.
449  * tty_setsofttab(on)   Turn on/off soft tab expansion.
450  * tty_islitecho()      Find out if typed control chars are echoed literally
451  * tty_setlitecho()     Turn on/off literal echo of control chars
452  * tty_tspeed(val)      Set transmit speed to val.
453  * tty_rspeed(val)      Set receive speed to val.
454  */
455
456
457 int
458 tty_linemode(void)
459 {
460 #ifndef USE_TERMIO
461         return(termbuf.state & TS_EXTPROC);
462 #else
463         return(termbuf.c_lflag & EXTPROC);
464 #endif
465 }
466
467 void
468 tty_setlinemode(int on)
469 {
470 #ifdef  TIOCEXT
471         set_termbuf();
472         (void) ioctl(pty, TIOCEXT, (char *)&on);
473         init_termbuf();
474 #else   /* !TIOCEXT */
475 # ifdef EXTPROC
476         if (on)
477                 termbuf.c_lflag |= EXTPROC;
478         else
479                 termbuf.c_lflag &= ~EXTPROC;
480 # endif
481 #endif  /* TIOCEXT */
482 }
483 #endif  /* LINEMODE */
484
485 int
486 tty_isecho(void)
487 {
488 #ifndef USE_TERMIO
489         return (termbuf.sg.sg_flags & ECHO);
490 #else
491         return (termbuf.c_lflag & ECHO);
492 #endif
493 }
494
495 int
496 tty_flowmode(void)
497 {
498 #ifndef USE_TERMIO
499         return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
500 #else
501         return((termbuf.c_iflag & IXON) ? 1 : 0);
502 #endif
503 }
504
505 int
506 tty_restartany(void)
507 {
508 #ifndef USE_TERMIO
509 # ifdef DECCTQ
510         return((termbuf.lflags & DECCTQ) ? 0 : 1);
511 # else
512         return(-1);
513 # endif
514 #else
515         return((termbuf.c_iflag & IXANY) ? 1 : 0);
516 #endif
517 }
518
519 void
520 tty_setecho(int on)
521 {
522 #ifndef USE_TERMIO
523         if (on)
524                 termbuf.sg.sg_flags |= ECHO|CRMOD;
525         else
526                 termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
527 #else
528         if (on)
529                 termbuf.c_lflag |= ECHO;
530         else
531                 termbuf.c_lflag &= ~ECHO;
532 #endif
533 }
534
535 int
536 tty_israw(void)
537 {
538 #ifndef USE_TERMIO
539         return(termbuf.sg.sg_flags & RAW);
540 #else
541         return(!(termbuf.c_lflag & ICANON));
542 #endif
543 }
544
545
546 void
547 tty_binaryin(int on)
548 {
549 #ifndef USE_TERMIO
550         if (on)
551                 termbuf.lflags |= LPASS8;
552         else
553                 termbuf.lflags &= ~LPASS8;
554 #else
555         if (on) {
556                 termbuf.c_iflag &= ~ISTRIP;
557         } else {
558                 termbuf.c_iflag |= ISTRIP;
559         }
560 #endif
561 }
562
563 void
564 tty_binaryout(int on)
565 {
566 #ifndef USE_TERMIO
567         if (on)
568                 termbuf.lflags |= LLITOUT;
569         else
570                 termbuf.lflags &= ~LLITOUT;
571 #else
572         if (on) {
573                 termbuf.c_cflag &= ~(CSIZE|PARENB);
574                 termbuf.c_cflag |= CS8;
575                 termbuf.c_oflag &= ~OPOST;
576         } else {
577                 termbuf.c_cflag &= ~CSIZE;
578                 termbuf.c_cflag |= CS7|PARENB;
579                 termbuf.c_oflag |= OPOST;
580         }
581 #endif
582 }
583
584 int
585 tty_isbinaryin(void)
586 {
587 #ifndef USE_TERMIO
588         return(termbuf.lflags & LPASS8);
589 #else
590         return(!(termbuf.c_iflag & ISTRIP));
591 #endif
592 }
593
594 int
595 tty_isbinaryout(void)
596 {
597 #ifndef USE_TERMIO
598         return(termbuf.lflags & LLITOUT);
599 #else
600         return(!(termbuf.c_oflag&OPOST));
601 #endif
602 }
603
604 #ifdef  LINEMODE
605 int
606 tty_isediting(void)
607 {
608 #ifndef USE_TERMIO
609         return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
610 #else
611         return(termbuf.c_lflag & ICANON);
612 #endif
613 }
614
615 int
616 tty_istrapsig(void)
617 {
618 #ifndef USE_TERMIO
619         return(!(termbuf.sg.sg_flags&RAW));
620 #else
621         return(termbuf.c_lflag & ISIG);
622 #endif
623 }
624
625 void
626 tty_setedit(int on)
627 {
628 #ifndef USE_TERMIO
629         if (on)
630                 termbuf.sg.sg_flags &= ~CBREAK;
631         else
632                 termbuf.sg.sg_flags |= CBREAK;
633 #else
634         if (on)
635                 termbuf.c_lflag |= ICANON;
636         else
637                 termbuf.c_lflag &= ~ICANON;
638 #endif
639 }
640
641 void
642 tty_setsig(int on)
643 {
644 #ifndef USE_TERMIO
645         if (on)
646                 ;
647 #else
648         if (on)
649                 termbuf.c_lflag |= ISIG;
650         else
651                 termbuf.c_lflag &= ~ISIG;
652 #endif
653 }
654 #endif  /* LINEMODE */
655
656 int
657 tty_issofttab(void)
658 {
659 #ifndef USE_TERMIO
660         return (termbuf.sg.sg_flags & XTABS);
661 #else
662 # ifdef OXTABS
663         return (termbuf.c_oflag & OXTABS);
664 # endif
665 # ifdef TABDLY
666         return ((termbuf.c_oflag & TABDLY) == TAB3);
667 # endif
668 #endif
669 }
670
671 void
672 tty_setsofttab(int on)
673 {
674 #ifndef USE_TERMIO
675         if (on)
676                 termbuf.sg.sg_flags |= XTABS;
677         else
678                 termbuf.sg.sg_flags &= ~XTABS;
679 #else
680         if (on) {
681 # ifdef OXTABS
682                 termbuf.c_oflag |= OXTABS;
683 # endif
684 # ifdef TABDLY
685                 termbuf.c_oflag &= ~TABDLY;
686                 termbuf.c_oflag |= TAB3;
687 # endif
688         } else {
689 # ifdef OXTABS
690                 termbuf.c_oflag &= ~OXTABS;
691 # endif
692 # ifdef TABDLY
693                 termbuf.c_oflag &= ~TABDLY;
694                 termbuf.c_oflag |= TAB0;
695 # endif
696         }
697 #endif
698 }
699
700 int
701 tty_islitecho(void)
702 {
703 #ifndef USE_TERMIO
704         return (!(termbuf.lflags & LCTLECH));
705 #else
706 # ifdef ECHOCTL
707         return (!(termbuf.c_lflag & ECHOCTL));
708 # endif
709 # ifdef TCTLECH
710         return (!(termbuf.c_lflag & TCTLECH));
711 # endif
712 # if    !defined(ECHOCTL) && !defined(TCTLECH)
713         return (0);     /* assumes ctl chars are echoed '^x' */
714 # endif
715 #endif
716 }
717
718 void
719 tty_setlitecho(int on)
720 {
721 #ifndef USE_TERMIO
722         if (on)
723                 termbuf.lflags &= ~LCTLECH;
724         else
725                 termbuf.lflags |= LCTLECH;
726 #else
727 # ifdef ECHOCTL
728         if (on)
729                 termbuf.c_lflag &= ~ECHOCTL;
730         else
731                 termbuf.c_lflag |= ECHOCTL;
732 # endif
733 # ifdef TCTLECH
734         if (on)
735                 termbuf.c_lflag &= ~TCTLECH;
736         else
737                 termbuf.c_lflag |= TCTLECH;
738 # endif
739 #endif
740 }
741
742 int
743 tty_iscrnl(void)
744 {
745 #ifndef USE_TERMIO
746         return (termbuf.sg.sg_flags & CRMOD);
747 #else
748         return (termbuf.c_iflag & ICRNL);
749 #endif
750 }
751
752 /*
753  * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
754  */
755 #if B4800 != 4800
756 #define DECODE_BAUD
757 #endif
758
759 #ifdef  DECODE_BAUD
760
761 /*
762  * A table of available terminal speeds
763  */
764 struct termspeeds {
765         int     speed;
766         int     value;
767 } termspeeds[] = {
768         { 0,      B0 },      { 50,    B50 },    { 75,     B75 },
769         { 110,    B110 },    { 134,   B134 },   { 150,    B150 },
770         { 200,    B200 },    { 300,   B300 },   { 600,    B600 },
771         { 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
772         { 4800,   B4800 },
773 #ifdef  B7200
774         { 7200,  B7200 },
775 #endif
776         { 9600,   B9600 },
777 #ifdef  B14400
778         { 14400,  B14400 },
779 #endif
780 #ifdef  B19200
781         { 19200,  B19200 },
782 #endif
783 #ifdef  B28800
784         { 28800,  B28800 },
785 #endif
786 #ifdef  B38400
787         { 38400,  B38400 },
788 #endif
789 #ifdef  B57600
790         { 57600,  B57600 },
791 #endif
792 #ifdef  B115200
793         { 115200, B115200 },
794 #endif
795 #ifdef  B230400
796         { 230400, B230400 },
797 #endif
798         { -1,     0 }
799 };
800 #endif  /* DECODE_BAUD */
801
802 void
803 tty_tspeed(int val)
804 {
805 #ifdef  DECODE_BAUD
806         struct termspeeds *tp;
807
808         for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
809                 ;
810         if (tp->speed == -1)    /* back up to last valid value */
811                 --tp;
812         cfsetospeed(&termbuf, tp->value);
813 #else   /* DECODE_BAUD */
814         cfsetospeed(&termbuf, val);
815 #endif  /* DECODE_BAUD */
816 }
817
818 void
819 tty_rspeed(int val)
820 {
821 #ifdef  DECODE_BAUD
822         struct termspeeds *tp;
823
824         for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
825                 ;
826         if (tp->speed == -1)    /* back up to last valid value */
827                 --tp;
828         cfsetispeed(&termbuf, tp->value);
829 #else   /* DECODE_BAUD */
830         cfsetispeed(&termbuf, val);
831 #endif  /* DECODE_BAUD */
832 }
833
834 /*
835  * getptyslave()
836  *
837  * Open the slave side of the pty, and do any initialization
838  * that is necessary.
839  */
840 static void
841 getptyslave(void)
842 {
843         int t = -1;
844         char erase;
845
846 # ifdef LINEMODE
847         int waslm;
848 # endif
849 # ifdef TIOCGWINSZ
850         struct winsize ws;
851         extern int def_row, def_col;
852 # endif
853         extern int def_tspeed, def_rspeed;
854         /*
855          * Opening the slave side may cause initilization of the
856          * kernel tty structure.  We need remember the state of
857          *      if linemode was turned on
858          *      terminal window size
859          *      terminal speed
860          *      erase character
861          * so that we can re-set them if we need to.
862          */
863 # ifdef LINEMODE
864         waslm = tty_linemode();
865 # endif
866         erase = termbuf.c_cc[VERASE];
867
868         /*
869          * Make sure that we don't have a controlling tty, and
870          * that we are the session (process group) leader.
871          */
872 # ifdef TIOCNOTTY
873         t = open(_PATH_TTY, O_RDWR);
874         if (t >= 0) {
875                 (void) ioctl(t, TIOCNOTTY, (char *)0);
876                 (void) close(t);
877         }
878 # endif
879
880         t = cleanopen(line);
881         if (t < 0)
882                 fatalperror(net, line);
883
884
885         /*
886          * set up the tty modes as we like them to be.
887          */
888         init_termbuf();
889 # ifdef TIOCGWINSZ
890         if (def_row || def_col) {
891                 memset((char *)&ws, 0, sizeof(ws));
892                 ws.ws_col = def_col;
893                 ws.ws_row = def_row;
894                 (void)ioctl(t, TIOCSWINSZ, (char *)&ws);
895         }
896 # endif
897
898         /*
899          * Settings for sgtty based systems
900          */
901 # ifndef        USE_TERMIO
902         termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
903 # endif /* USE_TERMIO */
904
905         /*
906          * Settings for all other termios/termio based
907          * systems, other than 4.4BSD.  In 4.4BSD the
908          * kernel does the initial terminal setup.
909          */
910         tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
911         tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
912         if (erase)
913                 termbuf.c_cc[VERASE] = erase;
914 # ifdef LINEMODE
915         if (waslm)
916                 tty_setlinemode(1);
917 # endif /* LINEMODE */
918
919         /*
920          * Set the tty modes, and make this our controlling tty.
921          */
922         set_termbuf();
923         if (login_tty(t) == -1)
924                 fatalperror(net, "login_tty");
925         if (net > 2)
926                 (void) close(net);
927 }
928
929 #ifndef O_NOCTTY
930 #define O_NOCTTY        0
931 #endif
932 /*
933  * Open the specified slave side of the pty,
934  * making sure that we have a clean tty.
935  */
936 int
937 cleanopen(char *li)
938 {
939         int t;
940
941         /*
942          * Make sure that other people can't open the
943          * slave side of the connection.
944          */
945         (void) chown(li, 0, 0);
946         (void) chmod(li, 0600);
947
948         (void) revoke(li);
949
950         t = open(line, O_RDWR|O_NOCTTY);
951
952         if (t < 0)
953                 return(-1);
954
955         return(t);
956 }
957
958 /*
959  * startslave(host)
960  *
961  * Given a hostname, do whatever
962  * is necessary to startup the login process on the slave side of the pty.
963  */
964
965 /* ARGSUSED */
966 void
967 startslave(char *host, int autologin, char *autoname)
968 {
969         int i;
970
971
972
973         if ((i = fork()) < 0)
974                 fatalperror(net, "fork");
975         if (i) {
976         } else {
977                 getptyslave();
978                 start_login(host, autologin, autoname);
979                 /*NOTREACHED*/
980         }
981 }
982
983 void
984 init_env(void)
985 {
986         char **envp;
987
988         envp = envinit;
989         if ((*envp = getenv("TZ")))
990                 *envp++ -= 3;
991         *envp = 0;
992         environ = envinit;
993 }
994
995
996 /*
997  * start_login(host)
998  *
999  * Assuming that we are now running as a child processes, this
1000  * function will turn us into the login process.
1001  */
1002
1003 #define undef1 __unused
1004
1005 void
1006 start_login(char *host undef1, int autologin undef1, char *name undef1)
1007 {
1008         char **argv;
1009
1010         scrub_env();
1011
1012         /*
1013          * -h : pass on name of host.
1014          *              WARNING:  -h is accepted by login if and only if
1015          *                      getuid() == 0.
1016          * -p : don't clobber the environment (so terminal type stays set).
1017          *
1018          * -f : force this login, he has already been authenticated
1019          */
1020         argv = addarg(0, "login");
1021
1022 #if     !defined(NO_LOGIN_H)
1023 #endif
1024 #if     !defined(NO_LOGIN_P)
1025         argv = addarg(argv, "-p");
1026 #endif
1027 #ifdef  LINEMODE
1028         /*
1029          * Set the environment variable "LINEMODE" to either
1030          * "real" or "kludge" if we are operating in either
1031          * real or kludge linemode.
1032          */
1033         if (lmodetype == REAL_LINEMODE)
1034                 setenv("LINEMODE", "real", 1);
1035 # ifdef KLUDGELINEMODE
1036         else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK)
1037                 setenv("LINEMODE", "kludge", 1);
1038 # endif
1039 #endif
1040 #ifdef  BFTPDAEMON
1041         /*
1042          * Are we working as the bftp daemon?  If so, then ask login
1043          * to start bftp instead of shell.
1044          */
1045         if (bftpd) {
1046                 argv = addarg(argv, "-e");
1047                 argv = addarg(argv, BFTPPATH);
1048         } else
1049 #endif
1050         if (getenv("USER")) {
1051                 argv = addarg(argv, "--");
1052                 argv = addarg(argv, getenv("USER"));
1053 #if     defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
1054                 {
1055                         char **cpp;
1056                         for (cpp = environ; *cpp; cpp++)
1057                                 argv = addarg(argv, *cpp);
1058                 }
1059 #endif
1060                 /*
1061                  * Assume that login will set the USER variable
1062                  * correctly.  For SysV systems, this means that
1063                  * USER will no longer be set, just LOGNAME by
1064                  * login.  (The problem is that if the auto-login
1065                  * fails, and the user then specifies a different
1066                  * account name, he can get logged in with both
1067                  * LOGNAME and USER in his environment, but the
1068                  * USER value will be wrong.
1069                  */
1070                 unsetenv("USER");
1071         }
1072         closelog();
1073
1074         if (altlogin == NULL) {
1075                 altlogin = _PATH_LOGIN;
1076         }
1077         execv(altlogin, argv);
1078
1079         syslog(LOG_ERR, "%s: %m", altlogin);
1080         fatalperror(net, altlogin);
1081         /*NOTREACHED*/
1082 }
1083
1084 static char **
1085 addarg(char **argv, const char *val)
1086 {
1087         char **cpp;
1088
1089         if (argv == NULL) {
1090                 /*
1091                  * 10 entries, a leading length, and a null
1092                  */
1093                 argv = (char **)malloc(sizeof(*argv) * 12);
1094                 if (argv == NULL)
1095                         return(NULL);
1096                 *argv++ = (char *)10;
1097                 *argv = (char *)0;
1098         }
1099         for (cpp = argv; *cpp; cpp++)
1100                 ;
1101         if (cpp == &argv[(long)argv[-1]]) {
1102                 --argv;
1103                 *argv = (char *)((long)(*argv) + 10);
1104                 argv = (char **)realloc(argv, sizeof(*argv)*((long)(*argv) + 2));
1105                 if (argv == NULL)
1106                         return(NULL);
1107                 argv++;
1108                 cpp = &argv[(long)argv[-1] - 10];
1109         }
1110         *cpp++ = strdup(val);
1111         *cpp = 0;
1112         return(argv);
1113 }
1114
1115 /*
1116  * scrub_env()
1117  *
1118  * We only accept the environment variables listed below.
1119  */
1120 void
1121 scrub_env(void)
1122 {
1123         static const char *rej[] = {
1124                 "TERMCAP=/",
1125                 NULL
1126         };
1127
1128         static const char *acc[] = {
1129                 "XAUTH=", "XAUTHORITY=", "DISPLAY=",
1130                 "TERM=",
1131                 "EDITOR=",
1132                 "PAGER=",
1133                 "LOGNAME=",
1134                 "POSIXLY_CORRECT=",
1135                 "PRINTER=",
1136                 NULL
1137         };
1138
1139         char **cpp, **cpp2;
1140         const char **p;
1141  
1142         for (cpp2 = cpp = environ; *cpp; cpp++) {
1143                 int reject_it = 0;
1144
1145                 for(p = rej; *p; p++)
1146                         if(strncmp(*cpp, *p, strlen(*p)) == 0) {
1147                                 reject_it = 1;
1148                                 break;
1149                         }
1150                 if (reject_it)
1151                         continue;
1152
1153                 for(p = acc; *p; p++)
1154                         if(strncmp(*cpp, *p, strlen(*p)) == 0)
1155                                 break;
1156                 if(*p != NULL)
1157                         *cpp2++ = *cpp;
1158         }
1159         *cpp2 = NULL;
1160 }
1161
1162 /*
1163  * cleanup()
1164  *
1165  * This is the routine to call when we are all through, to
1166  * clean up anything that needs to be cleaned up.
1167  */
1168 /* ARGSUSED */
1169 void
1170 cleanup(int sig __unused)
1171 {
1172         char *p;
1173         sigset_t mask;
1174
1175         p = line + sizeof(_PATH_DEV) - 1;
1176         /*
1177          * Block all signals before clearing the utmp entry.  We don't want to
1178          * be called again after calling logout() and then not add the wtmp
1179          * entry because of not finding the corresponding entry in utmp.
1180          */
1181         sigfillset(&mask);
1182         sigprocmask(SIG_SETMASK, &mask, NULL);
1183         if (logout(p))
1184                 logwtmp(p, "", "");
1185         (void)chmod(line, 0666);
1186         (void)chown(line, 0, 0);
1187         *p = 'p';
1188         (void)chmod(line, 0666);
1189         (void)chown(line, 0, 0);
1190         (void) shutdown(net, 2);
1191         _exit(1);
1192 }