]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - contrib/telnet/telnetd/sys_term.c
Fix possible login(1) argument injection in telnetd(8). [SA-16:36]
[FreeBSD/releng/9.3.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
1030         scrub_env();
1031
1032         /*
1033          * -h : pass on name of host.
1034          *              WARNING:  -h is accepted by login if and only if
1035          *                      getuid() == 0.
1036          * -p : don't clobber the environment (so terminal type stays set).
1037          *
1038          * -f : force this login, he has already been authenticated
1039          */
1040         argv = addarg(0, "login");
1041
1042 #if     !defined(NO_LOGIN_H)
1043 #ifdef  AUTHENTICATION
1044 # if    defined(NO_LOGIN_F) && defined(LOGIN_R)
1045         /*
1046          * Don't add the "-h host" option if we are going
1047          * to be adding the "-r host" option down below...
1048          */
1049         if ((auth_level < 0) || (autologin != AUTH_VALID))
1050 # endif
1051         {
1052                 argv = addarg(argv, "-h");
1053                 argv = addarg(argv, host);
1054         }
1055 #endif /* AUTHENTICATION */
1056 #endif
1057 #if     !defined(NO_LOGIN_P)
1058         argv = addarg(argv, "-p");
1059 #endif
1060 #ifdef  LINEMODE
1061         /*
1062          * Set the environment variable "LINEMODE" to either
1063          * "real" or "kludge" if we are operating in either
1064          * real or kludge linemode.
1065          */
1066         if (lmodetype == REAL_LINEMODE)
1067                 setenv("LINEMODE", "real", 1);
1068 # ifdef KLUDGELINEMODE
1069         else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK)
1070                 setenv("LINEMODE", "kludge", 1);
1071 # endif
1072 #endif
1073 #ifdef  BFTPDAEMON
1074         /*
1075          * Are we working as the bftp daemon?  If so, then ask login
1076          * to start bftp instead of shell.
1077          */
1078         if (bftpd) {
1079                 argv = addarg(argv, "-e");
1080                 argv = addarg(argv, BFTPPATH);
1081         } else
1082 #endif
1083 #ifdef  AUTHENTICATION
1084         if (auth_level >= 0 && autologin == AUTH_VALID) {
1085 # if    !defined(NO_LOGIN_F)
1086                 argv = addarg(argv, "-f");
1087                 argv = addarg(argv, "--");
1088                 argv = addarg(argv, name);
1089 # else
1090 #  if defined(LOGIN_R)
1091                 /*
1092                  * We don't have support for "login -f", but we
1093                  * can fool /bin/login into thinking that we are
1094                  * rlogind, and allow us to log in without a
1095                  * password.  The rlogin protocol expects
1096                  *      local-user\0remote-user\0term/speed\0
1097                  */
1098
1099                 if (pty > 2) {
1100                         char *cp;
1101                         char speed[128];
1102                         int isecho, israw, xpty, len;
1103                         extern int def_rspeed;
1104 #  ifndef LOGIN_HOST
1105                         /*
1106                          * Tell login that we are coming from "localhost".
1107                          * If we passed in the real host name, then the
1108                          * user would have to allow .rhost access from
1109                          * every machine that they want authenticated
1110                          * access to work from, which sort of defeats
1111                          * the purpose of an authenticated login...
1112                          * So, we tell login that the session is coming
1113                          * from "localhost", and the user will only have
1114                          * to have "localhost" in their .rhost file.
1115                          */
1116 #                       define LOGIN_HOST "localhost"
1117 #  endif
1118                         argv = addarg(argv, "-r");
1119                         argv = addarg(argv, LOGIN_HOST);
1120
1121                         xpty = pty;
1122                         pty = 0;
1123                         init_termbuf();
1124                         isecho = tty_isecho();
1125                         israw = tty_israw();
1126                         if (isecho || !israw) {
1127                                 tty_setecho(0);         /* Turn off echo */
1128                                 tty_setraw(1);          /* Turn on raw */
1129                                 set_termbuf();
1130                         }
1131                         len = strlen(name)+1;
1132                         write(xpty, name, len);
1133                         write(xpty, name, len);
1134                         snprintf(speed, sizeof(speed),
1135                                 "%s/%d", (cp = getenv("TERM")) ? cp : "",
1136                                 (def_rspeed > 0) ? def_rspeed : 9600);
1137                         len = strlen(speed)+1;
1138                         write(xpty, speed, len);
1139
1140                         if (isecho || !israw) {
1141                                 init_termbuf();
1142                                 tty_setecho(isecho);
1143                                 tty_setraw(israw);
1144                                 set_termbuf();
1145                                 if (!israw) {
1146                                         /*
1147                                          * Write a newline to ensure
1148                                          * that login will be able to
1149                                          * read the line...
1150                                          */
1151                                         write(xpty, "\n", 1);
1152                                 }
1153                         }
1154                         pty = xpty;
1155                 }
1156 #  else
1157                 argv = addarg(argv, "--");
1158                 argv = addarg(argv, name);
1159 #  endif
1160 # endif
1161         } else
1162 #endif
1163         if (getenv("USER")) {
1164                 argv = addarg(argv, "--");
1165                 argv = addarg(argv, getenv("USER"));
1166 #if     defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
1167                 {
1168                         char **cpp;
1169                         for (cpp = environ; *cpp; cpp++)
1170                                 argv = addarg(argv, *cpp);
1171                 }
1172 #endif
1173                 /*
1174                  * Assume that login will set the USER variable
1175                  * correctly.  For SysV systems, this means that
1176                  * USER will no longer be set, just LOGNAME by
1177                  * login.  (The problem is that if the auto-login
1178                  * fails, and the user then specifies a different
1179                  * account name, he can get logged in with both
1180                  * LOGNAME and USER in his environment, but the
1181                  * USER value will be wrong.
1182                  */
1183                 unsetenv("USER");
1184         }
1185 #ifdef  AUTHENTICATION
1186 #if     defined(NO_LOGIN_F) && defined(LOGIN_R)
1187         if (pty > 2)
1188                 close(pty);
1189 #endif
1190 #endif /* AUTHENTICATION */
1191         closelog();
1192
1193         if (altlogin == NULL) {
1194                 altlogin = _PATH_LOGIN;
1195         }
1196         execv(altlogin, argv);
1197
1198         syslog(LOG_ERR, "%s: %m", altlogin);
1199         fatalperror(net, altlogin);
1200         /*NOTREACHED*/
1201 }
1202
1203 static char **
1204 addarg(char **argv, const char *val)
1205 {
1206         char **cpp;
1207
1208         if (argv == NULL) {
1209                 /*
1210                  * 10 entries, a leading length, and a null
1211                  */
1212                 argv = (char **)malloc(sizeof(*argv) * 12);
1213                 if (argv == NULL)
1214                         fatal(net, "failure allocating argument space");
1215                 *argv++ = (char *)10;
1216                 *argv = (char *)0;
1217         }
1218         for (cpp = argv; *cpp; cpp++)
1219                 ;
1220         if (cpp == &argv[(long)argv[-1]]) {
1221                 --argv;
1222                 *argv = (char *)((long)(*argv) + 10);
1223                 argv = (char **)realloc(argv, sizeof(*argv)*((long)(*argv) + 2));
1224                 if (argv == NULL)
1225                         fatal(net, "failure allocating argument space");
1226                 argv++;
1227                 cpp = &argv[(long)argv[-1] - 10];
1228         }
1229         if ((*cpp++ = strdup(val)) == NULL)
1230                 fatal(net, "failure allocating argument space");
1231         *cpp = 0;
1232         return(argv);
1233 }
1234
1235 /*
1236  * scrub_env()
1237  *
1238  * We only accept the environment variables listed below.
1239  */
1240 void
1241 scrub_env(void)
1242 {
1243         static const char *rej[] = {
1244                 "TERMCAP=/",
1245                 NULL
1246         };
1247
1248         static const char *acc[] = {
1249                 "XAUTH=", "XAUTHORITY=", "DISPLAY=",
1250                 "TERM=",
1251                 "EDITOR=",
1252                 "PAGER=",
1253                 "LOGNAME=",
1254                 "POSIXLY_CORRECT=",
1255                 "PRINTER=",
1256                 NULL
1257         };
1258
1259         char **cpp, **cpp2;
1260         const char **p;
1261         char ** new_environ;
1262         size_t count;
1263
1264         /* Allocate space for scrubbed environment. */
1265         for (count = 1, cpp = environ; *cpp; count++, cpp++)
1266                 continue;
1267         if ((new_environ = malloc(count * sizeof(char *))) == NULL) {
1268                 environ = NULL;
1269                 return;
1270         }
1271
1272         for (cpp2 = new_environ, cpp = environ; *cpp; cpp++) {
1273                 int reject_it = 0;
1274
1275                 for(p = rej; *p; p++)
1276                         if(strncmp(*cpp, *p, strlen(*p)) == 0) {
1277                                 reject_it = 1;
1278                                 break;
1279                         }
1280                 if (reject_it)
1281                         continue;
1282
1283                 for(p = acc; *p; p++)
1284                         if(strncmp(*cpp, *p, strlen(*p)) == 0)
1285                                 break;
1286                 if(*p != NULL) {
1287                         if ((*cpp2++ = strdup(*cpp)) == NULL) {
1288                                 environ = new_environ;
1289                                 return;
1290                         }
1291                 }
1292         }
1293         *cpp2 = NULL;
1294         environ = new_environ;
1295 }
1296
1297 /*
1298  * cleanup()
1299  *
1300  * This is the routine to call when we are all through, to
1301  * clean up anything that needs to be cleaned up.
1302  */
1303 /* ARGSUSED */
1304 void
1305 cleanup(int sig __unused)
1306 {
1307
1308         (void) shutdown(net, SHUT_RDWR);
1309         _exit(1);
1310 }