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