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