Merge from vendor branch LESS:
[dragonfly.git] / libexec / telnetd / sys_term.c
1  /*
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)sys_term.c       8.4+1 (Berkeley) 5/30/95
34  * $FreeBSD: src/libexec/telnetd/sys_term.c,v 1.24.2.8 2002/06/17 02:48:06 jmallett Exp $
35  * $DragonFly: src/libexec/telnetd/sys_term.c,v 1.4 2007/05/18 17:05:12 dillon Exp $
36  */
37
38 #include <sys/types.h>
39 #include <sys/tty.h>
40 #include <libutil.h>
41 #include <stdlib.h>
42 #include <utmp.h>
43
44 #include "telnetd.h"
45 #include "pathnames.h"
46
47
48 int cleanopen(char *);
49 void scrub_env(void);
50
51 struct  utmp wtmp;
52
53 #ifdef _PATH_WTMP
54 char    wtmpf[] = _PATH_WTMP;
55 #else
56 char    wtmpf[] = "/var/log/wtmp";
57 #endif
58 #ifdef _PATH_UTMP
59 char    utmpf[] = _PATH_UTMP;
60 #else
61 char    utmpf[] = "/var/run/utmp";
62 #endif
63
64 char    *envinit[3];
65 extern char **environ;
66
67 #define SCPYN(a, b)     (void) strncpy(a, b, sizeof(a))
68 #define SCMPN(a, b)     strncmp(a, b, sizeof(a))
69
70 #ifdef  t_erase
71 #undef  t_erase
72 #undef  t_kill
73 #undef  t_intrc
74 #undef  t_quitc
75 #undef  t_startc
76 #undef  t_stopc
77 #undef  t_eofc
78 #undef  t_brkc
79 #undef  t_suspc
80 #undef  t_dsuspc
81 #undef  t_rprntc
82 #undef  t_flushc
83 #undef  t_werasc
84 #undef  t_lnextc
85 #endif
86
87 #ifndef USE_TERMIO
88 struct termbuf {
89         struct sgttyb sg;
90         struct tchars tc;
91         struct ltchars ltc;
92         int state;
93         int lflags;
94 } termbuf, termbuf2;
95 # define        cfsetospeed(tp, val)    (tp)->sg.sg_ospeed = (val)
96 # define        cfsetispeed(tp, val)    (tp)->sg.sg_ispeed = (val)
97 # define        cfgetospeed(tp)         (tp)->sg.sg_ospeed
98 # define        cfgetispeed(tp)         (tp)->sg.sg_ispeed
99 #else   /* USE_TERMIO */
100 # ifndef        TCSANOW
101 #  ifdef TCSETS
102 #   define      TCSANOW         TCSETS
103 #   define      TCSADRAIN       TCSETSW
104 #   define      tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
105 #  else
106 #   ifdef TCSETA
107 #    define     TCSANOW         TCSETA
108 #    define     TCSADRAIN       TCSETAW
109 #    define     tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
110 #   else
111 #    define     TCSANOW         TIOCSETA
112 #    define     TCSADRAIN       TIOCSETAW
113 #    define     tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
114 #   endif
115 #  endif
116 #  define       tcsetattr(f, a, t)      ioctl(f, a, t)
117 #  define       cfsetospeed(tp, val)    (tp)->c_cflag &= ~CBAUD; \
118                                         (tp)->c_cflag |= (val)
119 #  define       cfgetospeed(tp)         ((tp)->c_cflag & CBAUD)
120 #  ifdef CIBAUD
121 #   define      cfsetispeed(tp, val)    (tp)->c_cflag &= ~CIBAUD; \
122                                         (tp)->c_cflag |= ((val)<<IBSHIFT)
123 #   define      cfgetispeed(tp)         (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
124 #  else
125 #   define      cfsetispeed(tp, val)    (tp)->c_cflag &= ~CBAUD; \
126                                         (tp)->c_cflag |= (val)
127 #   define      cfgetispeed(tp)         ((tp)->c_cflag & CBAUD)
128 #  endif
129 # endif /* TCSANOW */
130 struct termios termbuf, termbuf2;       /* pty control structure */
131 #endif  /* USE_TERMIO */
132
133 #include <sys/types.h>
134 #include <libutil.h>
135
136 int cleanopen(char *);
137 void scrub_env(void);
138 static char **addarg(char **, const char *);
139
140 /*
141  * init_termbuf()
142  * copy_termbuf(cp)
143  * set_termbuf()
144  *
145  * These three routines are used to get and set the "termbuf" structure
146  * to and from the kernel.  init_termbuf() gets the current settings.
147  * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
148  * set_termbuf() writes the structure into the kernel.
149  */
150
151 void
152 init_termbuf(void)
153 {
154 #ifndef USE_TERMIO
155         (void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg);
156         (void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc);
157         (void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc);
158 # ifdef TIOCGSTATE
159         (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
160 # endif
161 #else
162         (void) tcgetattr(pty, &termbuf);
163 #endif
164         termbuf2 = termbuf;
165 }
166
167 #if     defined(LINEMODE) && defined(TIOCPKT_IOCTL)
168 void
169 copy_termbuf(char *cp, size_t len)
170 {
171         if (len > sizeof(termbuf))
172                 len = sizeof(termbuf);
173         memmove((char *)&termbuf, cp, len);
174         termbuf2 = termbuf;
175 }
176 #endif  /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
177
178 void
179 set_termbuf(void)
180 {
181         /*
182          * Only make the necessary changes.
183          */
184 #ifndef USE_TERMIO
185         if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg,
186                                                         sizeof(termbuf.sg)))
187                 (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg);
188         if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc,
189                                                         sizeof(termbuf.tc)))
190                 (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
191         if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
192                                                         sizeof(termbuf.ltc)))
193                 (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
194         if (termbuf.lflags != termbuf2.lflags)
195                 (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
196 #else   /* USE_TERMIO */
197         if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
198                 (void) tcsetattr(pty, TCSANOW, &termbuf);
199 #endif  /* USE_TERMIO */
200 }
201
202
203 /*
204  * spcset(func, valp, valpp)
205  *
206  * This function takes various special characters (func), and
207  * sets *valp to the current value of that character, and
208  * *valpp to point to where in the "termbuf" structure that
209  * value is kept.
210  *
211  * It returns the SLC_ level of support for this function.
212  */
213
214 #ifndef USE_TERMIO
215 int
216 spcset(int func, cc_t *valp, cc_t **valpp)
217 {
218         switch(func) {
219         case SLC_EOF:
220                 *valp = termbuf.tc.t_eofc;
221                 *valpp = (cc_t *)&termbuf.tc.t_eofc;
222                 return(SLC_VARIABLE);
223         case SLC_EC:
224                 *valp = termbuf.sg.sg_erase;
225                 *valpp = (cc_t *)&termbuf.sg.sg_erase;
226                 return(SLC_VARIABLE);
227         case SLC_EL:
228                 *valp = termbuf.sg.sg_kill;
229                 *valpp = (cc_t *)&termbuf.sg.sg_kill;
230                 return(SLC_VARIABLE);
231         case SLC_IP:
232                 *valp = termbuf.tc.t_intrc;
233                 *valpp = (cc_t *)&termbuf.tc.t_intrc;
234                 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
235         case SLC_ABORT:
236                 *valp = termbuf.tc.t_quitc;
237                 *valpp = (cc_t *)&termbuf.tc.t_quitc;
238                 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
239         case SLC_XON:
240                 *valp = termbuf.tc.t_startc;
241                 *valpp = (cc_t *)&termbuf.tc.t_startc;
242                 return(SLC_VARIABLE);
243         case SLC_XOFF:
244                 *valp = termbuf.tc.t_stopc;
245                 *valpp = (cc_t *)&termbuf.tc.t_stopc;
246                 return(SLC_VARIABLE);
247         case SLC_AO:
248                 *valp = termbuf.ltc.t_flushc;
249                 *valpp = (cc_t *)&termbuf.ltc.t_flushc;
250                 return(SLC_VARIABLE);
251         case SLC_SUSP:
252                 *valp = termbuf.ltc.t_suspc;
253                 *valpp = (cc_t *)&termbuf.ltc.t_suspc;
254                 return(SLC_VARIABLE);
255         case SLC_EW:
256                 *valp = termbuf.ltc.t_werasc;
257                 *valpp = (cc_t *)&termbuf.ltc.t_werasc;
258                 return(SLC_VARIABLE);
259         case SLC_RP:
260                 *valp = termbuf.ltc.t_rprntc;
261                 *valpp = (cc_t *)&termbuf.ltc.t_rprntc;
262                 return(SLC_VARIABLE);
263         case SLC_LNEXT:
264                 *valp = termbuf.ltc.t_lnextc;
265                 *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
266                 return(SLC_VARIABLE);
267         case SLC_FORW1:
268                 *valp = termbuf.tc.t_brkc;
269                 *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
270                 return(SLC_VARIABLE);
271         case SLC_BRK:
272         case SLC_SYNCH:
273         case SLC_AYT:
274         case SLC_EOR:
275                 *valp = (cc_t)0;
276                 *valpp = (cc_t *)0;
277                 return(SLC_DEFAULT);
278         default:
279                 *valp = (cc_t)0;
280                 *valpp = (cc_t *)0;
281                 return(SLC_NOSUPPORT);
282         }
283 }
284
285 #else   /* USE_TERMIO */
286
287
288 #define setval(a, b)    *valp = termbuf.c_cc[a]; \
289                         *valpp = &termbuf.c_cc[a]; \
290                         return(b);
291 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
292
293 int
294 spcset(int func, cc_t *valp, cc_t **valpp)
295 {
296         switch(func) {
297         case SLC_EOF:
298                 setval(VEOF, SLC_VARIABLE);
299         case SLC_EC:
300                 setval(VERASE, SLC_VARIABLE);
301         case SLC_EL:
302                 setval(VKILL, SLC_VARIABLE);
303         case SLC_IP:
304                 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
305         case SLC_ABORT:
306                 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
307         case SLC_XON:
308 #ifdef  VSTART
309                 setval(VSTART, SLC_VARIABLE);
310 #else
311                 defval(0x13);
312 #endif
313         case SLC_XOFF:
314 #ifdef  VSTOP
315                 setval(VSTOP, SLC_VARIABLE);
316 #else
317                 defval(0x11);
318 #endif
319         case SLC_EW:
320 #ifdef  VWERASE
321                 setval(VWERASE, SLC_VARIABLE);
322 #else
323                 defval(0);
324 #endif
325         case SLC_RP:
326 #ifdef  VREPRINT
327                 setval(VREPRINT, SLC_VARIABLE);
328 #else
329                 defval(0);
330 #endif
331         case SLC_LNEXT:
332 #ifdef  VLNEXT
333                 setval(VLNEXT, SLC_VARIABLE);
334 #else
335                 defval(0);
336 #endif
337         case SLC_AO:
338 #if     !defined(VDISCARD) && defined(VFLUSHO)
339 # define VDISCARD VFLUSHO
340 #endif
341 #ifdef  VDISCARD
342                 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
343 #else
344                 defval(0);
345 #endif
346         case SLC_SUSP:
347 #ifdef  VSUSP
348                 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
349 #else
350                 defval(0);
351 #endif
352 #ifdef  VEOL
353         case SLC_FORW1:
354                 setval(VEOL, SLC_VARIABLE);
355 #endif
356 #ifdef  VEOL2
357         case SLC_FORW2:
358                 setval(VEOL2, SLC_VARIABLE);
359 #endif
360         case SLC_AYT:
361 #ifdef  VSTATUS
362                 setval(VSTATUS, SLC_VARIABLE);
363 #else
364                 defval(0);
365 #endif
366
367         case SLC_BRK:
368         case SLC_SYNCH:
369         case SLC_EOR:
370                 defval(0);
371
372         default:
373                 *valp = 0;
374                 *valpp = 0;
375                 return(SLC_NOSUPPORT);
376         }
377 }
378 #endif  /* USE_TERMIO */
379
380 /*
381  * getpty()
382  *
383  * Allocate a pty.  As a side effect, the external character
384  * array "line" contains the name of the slave side.
385  *
386  * Returns the file descriptor of the opened pty.
387  */
388 char alpha[] = "0123456789abcdefghijklmnopqrstuv";
389 char line[16];
390
391 int
392 getpty(int *ptynum __unused)
393 {
394         int p;
395         const char *cp;
396         char *p1, *p2;
397         int i;
398
399         (void) strcpy(line, _PATH_DEV);
400         (void) strcat(line, "ptyXX");
401         p1 = &line[8];
402         p2 = &line[9];
403
404         for (cp = "pqrsPQRS"; *cp; cp++) {
405                 struct stat stb;
406
407                 *p1 = *cp;
408                 *p2 = '0';
409                 /*
410                  * This stat() check is just to keep us from
411                  * looping through all 256 combinations if there
412                  * aren't that many ptys available.
413                  */
414                 if (stat(line, &stb) < 0)
415                         break;
416                 for (i = 0; i < 32; i++) {
417                         *p2 = alpha[i];
418                         p = open(line, 2);
419                         if (p > 0) {
420                                 line[5] = 't';
421                                 chown(line, 0, 0);
422                                 chmod(line, 0600);
423                                         return(p);
424                         }
425                 }
426         }
427         return(-1);
428 }
429
430 #ifdef  LINEMODE
431 /*
432  * tty_flowmode()       Find out if flow control is enabled or disabled.
433  * tty_linemode()       Find out if linemode (external processing) is enabled.
434  * tty_setlinemod(on)   Turn on/off linemode.
435  * tty_isecho()         Find out if echoing is turned on.
436  * tty_setecho(on)      Enable/disable character echoing.
437  * tty_israw()          Find out if terminal is in RAW mode.
438  * tty_binaryin(on)     Turn on/off BINARY on input.
439  * tty_binaryout(on)    Turn on/off BINARY on output.
440  * tty_isediting()      Find out if line editing is enabled.
441  * tty_istrapsig()      Find out if signal trapping is enabled.
442  * tty_setedit(on)      Turn on/off line editing.
443  * tty_setsig(on)       Turn on/off signal trapping.
444  * tty_issofttab()      Find out if tab expansion is enabled.
445  * tty_setsofttab(on)   Turn on/off soft tab expansion.
446  * tty_islitecho()      Find out if typed control chars are echoed literally
447  * tty_setlitecho()     Turn on/off literal echo of control chars
448  * tty_tspeed(val)      Set transmit speed to val.
449  * tty_rspeed(val)      Set receive speed to val.
450  */
451
452
453 int
454 tty_linemode(void)
455 {
456 #ifndef USE_TERMIO
457         return(termbuf.state & TS_EXTPROC);
458 #else
459         return(termbuf.c_lflag & EXTPROC);
460 #endif
461 }
462
463 void
464 tty_setlinemode(int on)
465 {
466 #ifdef  TIOCEXT
467         set_termbuf();
468         (void) ioctl(pty, TIOCEXT, (char *)&on);
469         init_termbuf();
470 #else   /* !TIOCEXT */
471 # ifdef EXTPROC
472         if (on)
473                 termbuf.c_lflag |= EXTPROC;
474         else
475                 termbuf.c_lflag &= ~EXTPROC;
476 # endif
477 #endif  /* TIOCEXT */
478 }
479 #endif  /* LINEMODE */
480
481 int
482 tty_isecho(void)
483 {
484 #ifndef USE_TERMIO
485         return (termbuf.sg.sg_flags & ECHO);
486 #else
487         return (termbuf.c_lflag & ECHO);
488 #endif
489 }
490
491 int
492 tty_flowmode(void)
493 {
494 #ifndef USE_TERMIO
495         return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
496 #else
497         return((termbuf.c_iflag & IXON) ? 1 : 0);
498 #endif
499 }
500
501 int
502 tty_restartany(void)
503 {
504 #ifndef USE_TERMIO
505 # ifdef DECCTQ
506         return((termbuf.lflags & DECCTQ) ? 0 : 1);
507 # else
508         return(-1);
509 # endif
510 #else
511         return((termbuf.c_iflag & IXANY) ? 1 : 0);
512 #endif
513 }
514
515 void
516 tty_setecho(int on)
517 {
518 #ifndef USE_TERMIO
519         if (on)
520                 termbuf.sg.sg_flags |= ECHO|CRMOD;
521         else
522                 termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
523 #else
524         if (on)
525                 termbuf.c_lflag |= ECHO;
526         else
527                 termbuf.c_lflag &= ~ECHO;
528 #endif
529 }
530
531 int
532 tty_israw(void)
533 {
534 #ifndef USE_TERMIO
535         return(termbuf.sg.sg_flags & RAW);
536 #else
537         return(!(termbuf.c_lflag & ICANON));
538 #endif
539 }
540
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, (char *)0);
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 }
924
925 #ifndef O_NOCTTY
926 #define O_NOCTTY        0
927 #endif
928 /*
929  * Open the specified slave side of the pty,
930  * making sure that we have a clean tty.
931  */
932 int
933 cleanopen(char *li)
934 {
935         int t;
936
937         /*
938          * Make sure that other people can't open the
939          * slave side of the connection.
940          */
941         (void) chown(li, 0, 0);
942         (void) chmod(li, 0600);
943
944         (void) revoke(li);
945
946         t = open(line, O_RDWR|O_NOCTTY);
947
948         if (t < 0)
949                 return(-1);
950
951         return(t);
952 }
953
954 /*
955  * startslave(host)
956  *
957  * Given a hostname, do whatever
958  * is necessary to startup the login process on the slave side of the pty.
959  */
960
961 /* ARGSUSED */
962 void
963 startslave(char *host, int autologin, char *autoname)
964 {
965         int i;
966
967
968
969         if ((i = fork()) < 0)
970                 fatalperror(net, "fork");
971         if (i) {
972         } else {
973                 getptyslave();
974                 start_login(host, autologin, autoname);
975                 /*NOTREACHED*/
976         }
977 }
978
979 void
980 init_env(void)
981 {
982         char **envp;
983
984         envp = envinit;
985         if ((*envp = getenv("TZ")))
986                 *envp++ -= 3;
987         *envp = 0;
988         environ = envinit;
989 }
990
991
992 /*
993  * start_login(host)
994  *
995  * Assuming that we are now running as a child processes, this
996  * function will turn us into the login process.
997  */
998
999 #define undef1 __unused
1000
1001 void
1002 start_login(char *host undef1, int autologin undef1, char *name undef1)
1003 {
1004         char **argv;
1005
1006         scrub_env();
1007
1008         /*
1009          * -h : pass on name of host.
1010          *              WARNING:  -h is accepted by login if and only if
1011          *                      getuid() == 0.
1012          * -p : don't clobber the environment (so terminal type stays set).
1013          *
1014          * -f : force this login, he has already been authenticated
1015          */
1016         argv = addarg(0, "login");
1017
1018 #if     !defined(NO_LOGIN_H)
1019 #endif
1020 #if     !defined(NO_LOGIN_P)
1021         argv = addarg(argv, "-p");
1022 #endif
1023 #ifdef  LINEMODE
1024         /*
1025          * Set the environment variable "LINEMODE" to either
1026          * "real" or "kludge" if we are operating in either
1027          * real or kludge linemode.
1028          */
1029         if (lmodetype == REAL_LINEMODE) {
1030                 if (setenv("LINEMODE", "real", 1) == -1)
1031                         syslog(LOG_ERR, "setenv: cannot set LINEMODE=real: %m");
1032         }
1033 # ifdef KLUDGELINEMODE
1034         else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK) {
1035                 if (setenv("LINEMODE", "kludge", 1) == -1)
1036                         syslog(LOG_ERR, "setenv: cannot set LINEMODE=kludge: %m");
1037         }
1038 # endif
1039 #endif
1040 #ifdef  BFTPDAEMON
1041         /*
1042          * Are we working as the bftp daemon?  If so, then ask login
1043          * to start bftp instead of shell.
1044          */
1045         if (bftpd) {
1046                 argv = addarg(argv, "-e");
1047                 argv = addarg(argv, BFTPPATH);
1048         } else
1049 #endif
1050         if (getenv("USER")) {
1051                 argv = addarg(argv, "--");
1052                 argv = addarg(argv, getenv("USER"));
1053 #if     defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
1054                 {
1055                         char **cpp;
1056                         for (cpp = environ; *cpp; cpp++)
1057                                 argv = addarg(argv, *cpp);
1058                 }
1059 #endif
1060                 /*
1061                  * Assume that login will set the USER variable
1062                  * correctly.  For SysV systems, this means that
1063                  * USER will no longer be set, just LOGNAME by
1064                  * login.  (The problem is that if the auto-login
1065                  * fails, and the user then specifies a different
1066                  * account name, he can get logged in with both
1067                  * LOGNAME and USER in his environment, but the
1068                  * USER value will be wrong.
1069                  */
1070                 unsetenv("USER");
1071         }
1072         closelog();
1073
1074         if (altlogin == NULL) {
1075                 altlogin = _PATH_LOGIN;
1076         }
1077         execv(altlogin, argv);
1078
1079         syslog(LOG_ERR, "%s: %m", altlogin);
1080         fatalperror(net, altlogin);
1081         /*NOTREACHED*/
1082 }
1083
1084 static char **
1085 addarg(char **argv, const char *val)
1086 {
1087         char **cpp;
1088
1089         if (argv == NULL) {
1090                 /*
1091                  * 10 entries, a leading length, and a null
1092                  */
1093                 argv = (char **)malloc(sizeof(*argv) * 12);
1094                 if (argv == NULL)
1095                         return(NULL);
1096                 *argv++ = (char *)10;
1097                 *argv = (char *)0;
1098         }
1099         for (cpp = argv; *cpp; cpp++)
1100                 ;
1101         if (cpp == &argv[(long)argv[-1]]) {
1102                 --argv;
1103                 *argv = (char *)((long)(*argv) + 10);
1104                 argv = (char **)realloc(argv, sizeof(*argv)*((long)(*argv) + 2));
1105                 if (argv == NULL)
1106                         return(NULL);
1107                 argv++;
1108                 cpp = &argv[(long)argv[-1] - 10];
1109         }
1110         *cpp++ = strdup(val);
1111         *cpp = 0;
1112         return(argv);
1113 }
1114
1115 /*
1116  * scrub_env()
1117  *
1118  * We only accept the environment variables listed below.
1119  */
1120 void
1121 scrub_env(void)
1122 {
1123         static const char *rej[] = {
1124                 "TERMCAP=/",
1125                 NULL
1126         };
1127
1128         static const char *acc[] = {
1129                 "XAUTH=", "XAUTHORITY=", "DISPLAY=",
1130                 "TERM=",
1131                 "EDITOR=",
1132                 "PAGER=",
1133                 "LOGNAME=",
1134                 "POSIXLY_CORRECT=",
1135                 "PRINTER=",
1136                 NULL
1137         };
1138
1139         char **cpp, **cpp2;
1140         const char **p;
1141  
1142         for (cpp2 = cpp = environ; *cpp; cpp++) {
1143                 int reject_it = 0;
1144
1145                 for(p = rej; *p; p++)
1146                         if(strncmp(*cpp, *p, strlen(*p)) == 0) {
1147                                 reject_it = 1;
1148                                 break;
1149                         }
1150                 if (reject_it)
1151                         continue;
1152
1153                 for(p = acc; *p; p++)
1154                         if(strncmp(*cpp, *p, strlen(*p)) == 0)
1155                                 break;
1156                 if(*p != NULL)
1157                         *cpp2++ = *cpp;
1158         }
1159         *cpp2 = NULL;
1160 }
1161
1162 /*
1163  * cleanup()
1164  *
1165  * This is the routine to call when we are all through, to
1166  * clean up anything that needs to be cleaned up.
1167  */
1168 /* ARGSUSED */
1169 void
1170 cleanup(int sig __unused)
1171 {
1172         char *p;
1173         sigset_t mask;
1174
1175         p = line + sizeof(_PATH_DEV) - 1;
1176         /*
1177          * Block all signals before clearing the utmp entry.  We don't want to
1178          * be called again after calling logout() and then not add the wtmp
1179          * entry because of not finding the corresponding entry in utmp.
1180          */
1181         sigfillset(&mask);
1182         sigprocmask(SIG_SETMASK, &mask, NULL);
1183         if (logout(p))
1184                 logwtmp(p, "", "");
1185         (void)chmod(line, 0666);
1186         (void)chown(line, 0, 0);
1187         *p = 'p';
1188         (void)chmod(line, 0666);
1189         (void)chown(line, 0, 0);
1190         (void) shutdown(net, SHUT_RDWR);
1191         _exit(1);
1192 }