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