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