sys_term.c revision 1.40 1 /* $NetBSD: sys_term.c,v 1.40 2003/09/19 05:54:46 itojun Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95";
36 #else
37 __RCSID("$NetBSD: sys_term.c,v 1.40 2003/09/19 05:54:46 itojun Exp $");
38 #endif
39 #endif /* not lint */
40
41 #include "telnetd.h"
42 #include "pathnames.h"
43
44 #include <util.h>
45
46 #include <sys/cdefs.h>
47
48 #include <utmp.h>
49 struct utmp wtmp;
50
51 #define SCPYN(a, b) (void) strncpy(a, b, sizeof(a))
52 #define SCMPN(a, b) strncmp(a, b, sizeof(a))
53
54 struct termios termbuf, termbuf2; /* pty control structure */
55
56 void getptyslave __P((void));
57 int cleanopen __P((char *));
58 char **addarg __P((char **, char *));
59 void scrub_env __P((void));
60 int getent __P((char *, char *));
61 char *getstr __P((const char *, char **));
62 #ifdef KRB5
63 extern void kerberos5_cleanup __P((void));
64 #endif
65
66 /*
67 * init_termbuf()
68 * copy_termbuf(cp)
69 * set_termbuf()
70 *
71 * These three routines are used to get and set the "termbuf" structure
72 * to and from the kernel. init_termbuf() gets the current settings.
73 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
74 * set_termbuf() writes the structure into the kernel.
75 */
76
77 void
78 init_termbuf()
79 {
80 (void) tcgetattr(pty, &termbuf);
81 termbuf2 = termbuf;
82 }
83
84 #if defined(LINEMODE) && defined(TIOCPKT_IOCTL)
85 void
86 copy_termbuf(cp, len)
87 char *cp;
88 int len;
89 {
90 if (len > sizeof(termbuf))
91 len = sizeof(termbuf);
92 memmove((char *)&termbuf, cp, len);
93 termbuf2 = termbuf;
94 }
95 #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
96
97 void
98 set_termbuf()
99 {
100 /*
101 * Only make the necessary changes.
102 */
103 if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
104 (void) tcsetattr(pty, TCSANOW, &termbuf);
105 }
106
107
108 /*
109 * spcset(func, valp, valpp)
110 *
111 * This function takes various special characters (func), and
112 * sets *valp to the current value of that character, and
113 * *valpp to point to where in the "termbuf" structure that
114 * value is kept.
115 *
116 * It returns the SLC_ level of support for this function.
117 */
118
119
120 int
121 spcset(func, valp, valpp)
122 int func;
123 cc_t *valp;
124 cc_t **valpp;
125 {
126
127 #define setval(a, b) *valp = termbuf.c_cc[a]; \
128 *valpp = &termbuf.c_cc[a]; \
129 return(b);
130 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
131
132 switch(func) {
133 case SLC_EOF:
134 setval(VEOF, SLC_VARIABLE);
135 case SLC_EC:
136 setval(VERASE, SLC_VARIABLE);
137 case SLC_EL:
138 setval(VKILL, SLC_VARIABLE);
139 case SLC_IP:
140 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
141 case SLC_ABORT:
142 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
143 case SLC_XON:
144 setval(VSTART, SLC_VARIABLE);
145 case SLC_XOFF:
146 setval(VSTOP, SLC_VARIABLE);
147 case SLC_EW:
148 setval(VWERASE, SLC_VARIABLE);
149 case SLC_RP:
150 setval(VREPRINT, SLC_VARIABLE);
151 case SLC_LNEXT:
152 setval(VLNEXT, SLC_VARIABLE);
153 case SLC_AO:
154 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
155 case SLC_SUSP:
156 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
157 case SLC_FORW1:
158 setval(VEOL, SLC_VARIABLE);
159 case SLC_FORW2:
160 setval(VEOL2, SLC_VARIABLE);
161 case SLC_AYT:
162 setval(VSTATUS, SLC_VARIABLE);
163
164 case SLC_BRK:
165 case SLC_SYNCH:
166 case SLC_EOR:
167 defval(0);
168
169 default:
170 *valp = 0;
171 *valpp = 0;
172 return(SLC_NOSUPPORT);
173 }
174 }
175
176
177 /*
178 * getpty()
179 *
180 * Allocate a pty. As a side effect, the external character
181 * array "line" contains the name of the slave side.
182 *
183 * Returns the file descriptor of the opened pty.
184 */
185 #ifndef __GNUC__
186 char *line = NULL16STR;
187 #else
188 static char Xline[] = NULL16STR;
189 char *line = Xline;
190 #endif
191
192
193 static int ptyslavefd; /* for cleanopen() */
194
195 int
196 getpty(ptynum)
197 int *ptynum;
198 {
199 int ptyfd;
200
201 ptyfd = openpty(ptynum, &ptyslavefd, line, NULL, NULL);
202 if (ptyfd == 0)
203 return *ptynum;
204 ptyslavefd = -1;
205 return (-1);
206 }
207
208 #ifdef LINEMODE
209 /*
210 * tty_flowmode() Find out if flow control is enabled or disabled.
211 * tty_linemode() Find out if linemode (external processing) is enabled.
212 * tty_setlinemod(on) Turn on/off linemode.
213 * tty_isecho() Find out if echoing is turned on.
214 * tty_setecho(on) Enable/disable character echoing.
215 * tty_israw() Find out if terminal is in RAW mode.
216 * tty_binaryin(on) Turn on/off BINARY on input.
217 * tty_binaryout(on) Turn on/off BINARY on output.
218 * tty_isediting() Find out if line editing is enabled.
219 * tty_istrapsig() Find out if signal trapping is enabled.
220 * tty_setedit(on) Turn on/off line editing.
221 * tty_setsig(on) Turn on/off signal trapping.
222 * tty_issofttab() Find out if tab expansion is enabled.
223 * tty_setsofttab(on) Turn on/off soft tab expansion.
224 * tty_islitecho() Find out if typed control chars are echoed literally
225 * tty_setlitecho() Turn on/off literal echo of control chars
226 * tty_tspeed(val) Set transmit speed to val.
227 * tty_rspeed(val) Set receive speed to val.
228 */
229
230
231 int
232 tty_linemode()
233 {
234 return(termbuf.c_lflag & EXTPROC);
235 }
236
237 void
238 tty_setlinemode(on)
239 int on;
240 {
241 set_termbuf();
242 (void) ioctl(pty, TIOCEXT, (char *)&on);
243 init_termbuf();
244 }
245 #endif /* LINEMODE */
246
247 int
248 tty_isecho()
249 {
250 return (termbuf.c_lflag & ECHO);
251 }
252
253 int
254 tty_flowmode()
255 {
256 return((termbuf.c_iflag & IXON) ? 1 : 0);
257 }
258
259 int
260 tty_restartany()
261 {
262 return((termbuf.c_iflag & IXANY) ? 1 : 0);
263 }
264
265 void
266 tty_setecho(on)
267 int on;
268 {
269 if (on)
270 termbuf.c_lflag |= ECHO;
271 else
272 termbuf.c_lflag &= ~ECHO;
273 }
274
275 int
276 tty_israw()
277 {
278 return(!(termbuf.c_lflag & ICANON));
279 }
280
281 void
282 tty_binaryin(on)
283 int on;
284 {
285 if (on) {
286 termbuf.c_iflag &= ~ISTRIP;
287 } else {
288 termbuf.c_iflag |= ISTRIP;
289 }
290 }
291
292 void
293 tty_binaryout(on)
294 int on;
295 {
296 if (on) {
297 termbuf.c_cflag &= ~(CSIZE|PARENB);
298 termbuf.c_cflag |= CS8;
299 termbuf.c_oflag &= ~OPOST;
300 } else {
301 termbuf.c_cflag &= ~CSIZE;
302 termbuf.c_cflag |= CS7|PARENB;
303 termbuf.c_oflag |= OPOST;
304 }
305 }
306
307 int
308 tty_isbinaryin()
309 {
310 return(!(termbuf.c_iflag & ISTRIP));
311 }
312
313 int
314 tty_isbinaryout()
315 {
316 return(!(termbuf.c_oflag&OPOST));
317 }
318
319 #ifdef LINEMODE
320 int
321 tty_isediting()
322 {
323 return(termbuf.c_lflag & ICANON);
324 }
325
326 int
327 tty_istrapsig()
328 {
329 return(termbuf.c_lflag & ISIG);
330 }
331
332 void
333 tty_setedit(on)
334 int on;
335 {
336 if (on)
337 termbuf.c_lflag |= ICANON;
338 else
339 termbuf.c_lflag &= ~ICANON;
340 }
341
342 void
343 tty_setsig(on)
344 int on;
345 {
346 if (on)
347 termbuf.c_lflag |= ISIG;
348 else
349 termbuf.c_lflag &= ~ISIG;
350 }
351 #endif /* LINEMODE */
352
353 int
354 tty_issofttab()
355 {
356 # ifdef OXTABS
357 return (termbuf.c_oflag & OXTABS);
358 # endif
359 # ifdef TABDLY
360 return ((termbuf.c_oflag & TABDLY) == TAB3);
361 # endif
362 }
363
364 void
365 tty_setsofttab(on)
366 int on;
367 {
368 if (on) {
369 # ifdef OXTABS
370 termbuf.c_oflag |= OXTABS;
371 # endif
372 # ifdef TABDLY
373 termbuf.c_oflag &= ~TABDLY;
374 termbuf.c_oflag |= TAB3;
375 # endif
376 } else {
377 # ifdef OXTABS
378 termbuf.c_oflag &= ~OXTABS;
379 # endif
380 # ifdef TABDLY
381 termbuf.c_oflag &= ~TABDLY;
382 termbuf.c_oflag |= TAB0;
383 # endif
384 }
385 }
386
387 int
388 tty_islitecho()
389 {
390 # ifdef ECHOCTL
391 return (!(termbuf.c_lflag & ECHOCTL));
392 # endif
393 # ifdef TCTLECH
394 return (!(termbuf.c_lflag & TCTLECH));
395 # endif
396 # if !defined(ECHOCTL) && !defined(TCTLECH)
397 return (0); /* assumes ctl chars are echoed '^x' */
398 # endif
399 }
400
401 void
402 tty_setlitecho(on)
403 int on;
404 {
405 # ifdef ECHOCTL
406 if (on)
407 termbuf.c_lflag &= ~ECHOCTL;
408 else
409 termbuf.c_lflag |= ECHOCTL;
410 # endif
411 # ifdef TCTLECH
412 if (on)
413 termbuf.c_lflag &= ~TCTLECH;
414 else
415 termbuf.c_lflag |= TCTLECH;
416 # endif
417 }
418
419 int
420 tty_iscrnl()
421 {
422 return (termbuf.c_iflag & ICRNL);
423 }
424
425 void
426 tty_tspeed(val)
427 int val;
428 {
429 cfsetospeed(&termbuf, val);
430 }
431
432 void
433 tty_rspeed(val)
434 int val;
435 {
436 cfsetispeed(&termbuf, val);
437 }
438
439
440
441
442 /*
443 * getptyslave()
444 *
445 * Open the slave side of the pty, and do any initialization
446 * that is necessary. The return value is a file descriptor
447 * for the slave side.
448 */
449 extern int def_tspeed, def_rspeed;
450 extern int def_row, def_col;
451
452 void
453 getptyslave()
454 {
455 register int t = -1;
456
457 #ifdef LINEMODE
458 int waslm;
459 #endif
460 struct winsize ws;
461 /*
462 * Opening the slave side may cause initilization of the
463 * kernel tty structure. We need remember the state of
464 * if linemode was turned on
465 * terminal window size
466 * terminal speed
467 * so that we can re-set them if we need to.
468 */
469 #ifdef LINEMODE
470 waslm = tty_linemode();
471 #endif
472
473 /*
474 * Make sure that we don't have a controlling tty, and
475 * that we are the session (process group) leader.
476 */
477 t = open(_PATH_TTY, O_RDWR);
478 if (t >= 0) {
479 (void) ioctl(t, TIOCNOTTY, (char *)0);
480 (void) close(t);
481 }
482
483
484
485 t = cleanopen(line);
486 if (t < 0)
487 fatalperror(net, line);
488
489
490 /*
491 * set up the tty modes as we like them to be.
492 */
493 init_termbuf();
494 if (def_row || def_col) {
495 memset((char *)&ws, 0, sizeof(ws));
496 ws.ws_col = def_col;
497 ws.ws_row = def_row;
498 (void)ioctl(t, TIOCSWINSZ, (char *)&ws);
499 }
500
501 /*
502 * Settings for sgtty based systems
503 */
504
505 /*
506 * Settings for all other termios/termio based
507 * systems, other than 4.4BSD. In 4.4BSD the
508 * kernel does the initial terminal setup.
509 */
510 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
511 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
512 #ifdef LINEMODE
513 if (waslm)
514 tty_setlinemode(1);
515 #endif /* LINEMODE */
516
517 /*
518 * Set the tty modes, and make this our controlling tty.
519 */
520 set_termbuf();
521 if (login_tty(t) == -1)
522 fatalperror(net, "login_tty");
523 if (net > 2)
524 (void) close(net);
525 if (pty > 2) {
526 (void) close(pty);
527 pty = -1;
528 }
529 }
530
531 /*
532 * Open the specified slave side of the pty,
533 * making sure that we have a clean tty.
534 */
535 int
536 cleanopen(ttyline)
537 char *ttyline;
538 {
539 return ptyslavefd;
540 }
541
542 /*
543 * startslave(host)
544 *
545 * Given a hostname, do whatever
546 * is necessary to startup the login process on the slave side of the pty.
547 */
548
549 /* ARGSUSED */
550 void
551 startslave(host, autologin, autoname)
552 char *host;
553 int autologin;
554 char *autoname;
555 {
556 register int i;
557
558 #ifdef AUTHENTICATION
559 if (!autoname || !autoname[0])
560 autologin = 0;
561
562 if (autologin < auth_level) {
563 fatal(net, "Authorization failed");
564 exit(1);
565 }
566 #endif
567
568
569 if ((i = fork()) < 0)
570 fatalperror(net, "fork");
571 if (i) {
572 } else {
573 getptyslave();
574 start_login(host, autologin, autoname);
575 /*NOTREACHED*/
576 }
577 }
578
579 char *envinit[3];
580
581 void
582 init_env()
583 {
584 char **envp;
585
586 envp = envinit;
587 if ((*envp = getenv("TZ")))
588 *envp++ -= 3;
589 *envp = 0;
590 environ = envinit;
591 }
592
593
594 /*
595 * start_login(host)
596 *
597 * Assuming that we are now running as a child processes, this
598 * function will turn us into the login process.
599 */
600 extern char *gettyname;
601
602 void
603 start_login(host, autologin, name)
604 char *host;
605 int autologin;
606 char *name;
607 {
608 register char **argv;
609 #define TABBUFSIZ 512
610 char defent[TABBUFSIZ];
611 char defstrs[TABBUFSIZ];
612 #undef TABBUFSIZ
613 const char *loginprog = NULL;
614
615
616 scrub_env();
617
618 /*
619 * -h : pass on name of host.
620 * WARNING: -h is accepted by login if and only if
621 * getuid() == 0.
622 * -p : don't clobber the environment (so terminal type stays set).
623 *
624 * -f : force this login, he has already been authenticated
625 */
626 argv = addarg(0, "login");
627
628 {
629 argv = addarg(argv, "-h");
630 argv = addarg(argv, host);
631 }
632 argv = addarg(argv, "-p");
633 #ifdef LINEMODE
634 /*
635 * Set the environment variable "LINEMODE" to either
636 * "real" or "kludge" if we are operating in either
637 * real or kludge linemode.
638 */
639 if (lmodetype == REAL_LINEMODE)
640 setenv("LINEMODE", "real", 1);
641 # ifdef KLUDGELINEMODE
642 else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK)
643 setenv("LINEMODE", "kludge", 1);
644 # endif
645 #endif
646 #ifdef SECURELOGIN
647 /*
648 * don't worry about the -f that might get sent.
649 * A -s is supposed to override it anyhow.
650 */
651 if (require_secure_login)
652 argv = addarg(argv, "-s");
653 #endif
654 #ifdef AUTHENTICATION
655 if (auth_level >= 0 && autologin == AUTH_VALID) {
656 argv = addarg(argv, "-f");
657 argv = addarg(argv, "--");
658 argv = addarg(argv, name);
659 } else
660 #endif
661 if (getenv("USER")) {
662 argv = addarg(argv, "--");
663 argv = addarg(argv, getenv("USER"));
664 /*
665 * Assume that login will set the USER variable
666 * correctly. For SysV systems, this means that
667 * USER will no longer be set, just LOGNAME by
668 * login. (The problem is that if the auto-login
669 * fails, and the user then specifies a different
670 * account name, he can get logged in with both
671 * LOGNAME and USER in his environment, but the
672 * USER value will be wrong.
673 */
674 unsetenv("USER");
675 }
676 if (getent(defent, gettyname) == 1) {
677 char *cp = defstrs;
678
679 loginprog = getstr("lo", &cp);
680 }
681 if (loginprog == NULL)
682 loginprog = _PATH_LOGIN;
683 closelog();
684 /*
685 * This sleep(1) is in here so that telnetd can
686 * finish up with the tty. There's a race condition
687 * the login banner message gets lost...
688 */
689 sleep(1);
690 execv(loginprog, argv);
691
692 syslog(LOG_ERR, "%s: %m", loginprog);
693 fatalperror(net, loginprog);
694 /*NOTREACHED*/
695 }
696
697 char **
698 addarg(argv, val)
699 register char **argv;
700 register char *val;
701 {
702 register char **cpp;
703 char **nargv;
704
705 if (argv == NULL) {
706 /*
707 * 10 entries, a leading length, and a null
708 */
709 argv = (char **)malloc(sizeof(*argv) * 12);
710 if (argv == NULL)
711 return(NULL);
712 *argv++ = (char *)10;
713 *argv = (char *)0;
714 }
715 for (cpp = argv; *cpp; cpp++)
716 ;
717 if (cpp == &argv[(long)argv[-1]]) {
718 --argv;
719 nargv = (char **)realloc(argv,
720 sizeof(*argv) * ((long)(*argv) + 10 + 2));
721 if (argv == NULL) {
722 fatal(net, "not enough memory");
723 /*NOTREACHED*/
724 }
725 argv = nargv;
726 *argv = (char *)((long)(*argv) + 10);
727 argv++;
728 cpp = &argv[(long)argv[-1] - 10];
729 }
730 *cpp++ = val;
731 *cpp = 0;
732 return(argv);
733 }
734
735 /*
736 * scrub_env()
737 *
738 * We only accept the environment variables listed below.
739 */
740
741 void
742 scrub_env()
743 {
744 static const char *reject[] = {
745 "TERMCAP=/",
746 NULL
747 };
748
749 static const char *acceptstr[] = {
750 "XAUTH=", "XAUTHORITY=", "DISPLAY=",
751 "TERM=",
752 "EDITOR=",
753 "PAGER=",
754 "LOGNAME=",
755 "POSIXLY_CORRECT=",
756 "TERMCAP=",
757 "PRINTER=",
758 NULL
759 };
760
761 char **cpp, **cpp2;
762 const char **p;
763
764 for (cpp2 = cpp = environ; *cpp; cpp++) {
765 int reject_it = 0;
766
767 for(p = reject; *p; p++)
768 if(strncmp(*cpp, *p, strlen(*p)) == 0) {
769 reject_it = 1;
770 break;
771 }
772 if (reject_it)
773 continue;
774
775 for(p = acceptstr; *p; p++)
776 if(strncmp(*cpp, *p, strlen(*p)) == 0)
777 break;
778 if(*p != NULL)
779 *cpp2++ = *cpp;
780 }
781 *cpp2 = NULL;
782 }
783
784 /*
785 * cleanup()
786 *
787 * This is the routine to call when we are all through, to
788 * clean up anything that needs to be cleaned up.
789 */
790 /* ARGSUSED */
791 void
792 cleanup(sig)
793 int sig;
794 {
795 char *p, c;
796
797 p = line + sizeof("/dev/") - 1;
798 #ifdef SUPPORT_UTMP
799 if (logout(p))
800 logwtmp(p, "", "");
801 #endif
802 #ifdef SUPPORT_UTMPX
803 if (logoutx(p, 0, DEAD_PROCESS))
804 logwtmpx(p, "", "", 0, DEAD_PROCESS);
805 #endif
806 (void)chmod(line, 0666);
807 (void)chown(line, 0, 0);
808 c = *p; *p = 'p';
809 (void)chmod(line, 0666);
810 (void)chown(line, 0, 0);
811 *p = c;
812 if (ttyaction(line, "telnetd", "root"))
813 syslog(LOG_ERR, "%s: ttyaction failed", line);
814 (void) shutdown(net, 2);
815 exit(1);
816 }
817