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