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