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