MFC - FreeBSD-SA-09:05.telnet - fix environment based code execution vulnerability
[dragonfly.git] / crypto / heimdal-0.6.3 / appl / telnet / telnetd / sys_term.c
blob3875847d8d7323aaaf38c835f7be01135bf4be1a
1 /*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
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.
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.
34 #include "telnetd.h"
36 RCSID("$Id: sys_term.c,v 1.104 2001/09/17 02:09:04 assar Exp $");
38 #if defined(_CRAY) || (defined(__hpux) && !defined(HAVE_UTMPX_H))
39 # define PARENT_DOES_UTMP
40 #endif
42 #ifdef HAVE_UTMP_H
43 #include <utmp.h>
44 #endif
46 #ifdef HAVE_UTMPX_H
47 #include <utmpx.h>
48 #endif
50 #ifdef HAVE_UTMPX_H
51 struct utmpx wtmp;
52 #elif defined(HAVE_UTMP_H)
53 struct utmp wtmp;
54 #endif /* HAVE_UTMPX_H */
56 #ifdef HAVE_STRUCT_UTMP_UT_HOST
57 int utmp_len = sizeof(wtmp.ut_host);
58 #else
59 int utmp_len = MaxHostNameLen;
60 #endif
62 #ifndef UTMP_FILE
63 #ifdef _PATH_UTMP
64 #define UTMP_FILE _PATH_UTMP
65 #else
66 #define UTMP_FILE "/etc/utmp"
67 #endif
68 #endif
70 #if !defined(WTMP_FILE) && defined(_PATH_WTMP)
71 #define WTMP_FILE _PATH_WTMP
72 #endif
74 #ifndef PARENT_DOES_UTMP
75 #ifdef WTMP_FILE
76 char wtmpf[] = WTMP_FILE;
77 #else
78 char wtmpf[] = "/usr/adm/wtmp";
79 #endif
80 char utmpf[] = UTMP_FILE;
81 #else /* PARENT_DOES_UTMP */
82 #ifdef WTMP_FILE
83 char wtmpf[] = WTMP_FILE;
84 #else
85 char wtmpf[] = "/etc/wtmp";
86 #endif
87 #endif /* PARENT_DOES_UTMP */
89 #ifdef HAVE_TMPDIR_H
90 #include <tmpdir.h>
91 #endif /* CRAY */
93 #ifdef STREAMSPTY
95 #ifdef HAVE_SAC_H
96 #include <sac.h>
97 #endif
99 #ifdef HAVE_SYS_STROPTS_H
100 #include <sys/stropts.h>
101 #endif
103 #endif /* STREAMSPTY */
105 #undef NOERROR
107 #ifdef HAVE_SYS_STREAM_H
108 #ifdef HAVE_SYS_UIO_H
109 #include <sys/uio.h>
110 #endif
111 #ifdef __hpux
112 #undef SE
113 #endif
114 #include <sys/stream.h>
115 #endif
116 #if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY)
117 #include <sys/tty.h>
118 #endif
119 #ifdef t_erase
120 #undef t_erase
121 #undef t_kill
122 #undef t_intrc
123 #undef t_quitc
124 #undef t_startc
125 #undef t_stopc
126 #undef t_eofc
127 #undef t_brkc
128 #undef t_suspc
129 #undef t_dsuspc
130 #undef t_rprntc
131 #undef t_flushc
132 #undef t_werasc
133 #undef t_lnextc
134 #endif
136 #ifdef HAVE_TERMIOS_H
137 #include <termios.h>
138 #else
139 #ifdef HAVE_TERMIO_H
140 #include <termio.h>
141 #endif
142 #endif
144 #ifdef HAVE_UTIL_H
145 #include <util.h>
146 #endif
147 #ifdef HAVE_LIBUTIL_H
148 #include <libutil.h>
149 #endif
151 # ifndef TCSANOW
152 # ifdef TCSETS
153 # define TCSANOW TCSETS
154 # define TCSADRAIN TCSETSW
155 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
156 # else
157 # ifdef TCSETA
158 # define TCSANOW TCSETA
159 # define TCSADRAIN TCSETAW
160 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
161 # else
162 # define TCSANOW TIOCSETA
163 # define TCSADRAIN TIOCSETAW
164 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
165 # endif
166 # endif
167 # define tcsetattr(f, a, t) ioctl(f, a, t)
168 # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
169 (tp)->c_cflag |= (val)
170 # define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
171 # ifdef CIBAUD
172 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
173 (tp)->c_cflag |= ((val)<<IBSHIFT)
174 # define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
175 # else
176 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
177 (tp)->c_cflag |= (val)
178 # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
179 # endif
180 # endif /* TCSANOW */
181 struct termios termbuf, termbuf2; /* pty control structure */
182 # ifdef STREAMSPTY
183 static int ttyfd = -1;
184 int really_stream = 0;
185 # endif
187 const char *new_login = _PATH_LOGIN;
190 * init_termbuf()
191 * copy_termbuf(cp)
192 * set_termbuf()
194 * These three routines are used to get and set the "termbuf" structure
195 * to and from the kernel. init_termbuf() gets the current settings.
196 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
197 * set_termbuf() writes the structure into the kernel.
200 void
201 init_termbuf(void)
203 # ifdef STREAMSPTY
204 if (really_stream)
205 tcgetattr(ttyfd, &termbuf);
206 else
207 # endif
208 tcgetattr(ourpty, &termbuf);
209 termbuf2 = termbuf;
212 void
213 set_termbuf(void)
216 * Only make the necessary changes.
218 if (memcmp(&termbuf, &termbuf2, sizeof(termbuf)))
219 # ifdef STREAMSPTY
220 if (really_stream)
221 tcsetattr(ttyfd, TCSANOW, &termbuf);
222 else
223 # endif
224 tcsetattr(ourpty, TCSANOW, &termbuf);
229 * spcset(func, valp, valpp)
231 * This function takes various special characters (func), and
232 * sets *valp to the current value of that character, and
233 * *valpp to point to where in the "termbuf" structure that
234 * value is kept.
236 * It returns the SLC_ level of support for this function.
241 spcset(int func, cc_t *valp, cc_t **valpp)
244 #define setval(a, b) *valp = termbuf.c_cc[a]; \
245 *valpp = &termbuf.c_cc[a]; \
246 return(b);
247 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
249 switch(func) {
250 case SLC_EOF:
251 setval(VEOF, SLC_VARIABLE);
252 case SLC_EC:
253 setval(VERASE, SLC_VARIABLE);
254 case SLC_EL:
255 setval(VKILL, SLC_VARIABLE);
256 case SLC_IP:
257 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
258 case SLC_ABORT:
259 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
260 case SLC_XON:
261 #ifdef VSTART
262 setval(VSTART, SLC_VARIABLE);
263 #else
264 defval(0x13);
265 #endif
266 case SLC_XOFF:
267 #ifdef VSTOP
268 setval(VSTOP, SLC_VARIABLE);
269 #else
270 defval(0x11);
271 #endif
272 case SLC_EW:
273 #ifdef VWERASE
274 setval(VWERASE, SLC_VARIABLE);
275 #else
276 defval(0);
277 #endif
278 case SLC_RP:
279 #ifdef VREPRINT
280 setval(VREPRINT, SLC_VARIABLE);
281 #else
282 defval(0);
283 #endif
284 case SLC_LNEXT:
285 #ifdef VLNEXT
286 setval(VLNEXT, SLC_VARIABLE);
287 #else
288 defval(0);
289 #endif
290 case SLC_AO:
291 #if !defined(VDISCARD) && defined(VFLUSHO)
292 # define VDISCARD VFLUSHO
293 #endif
294 #ifdef VDISCARD
295 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
296 #else
297 defval(0);
298 #endif
299 case SLC_SUSP:
300 #ifdef VSUSP
301 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
302 #else
303 defval(0);
304 #endif
305 #ifdef VEOL
306 case SLC_FORW1:
307 setval(VEOL, SLC_VARIABLE);
308 #endif
309 #ifdef VEOL2
310 case SLC_FORW2:
311 setval(VEOL2, SLC_VARIABLE);
312 #endif
313 case SLC_AYT:
314 #ifdef VSTATUS
315 setval(VSTATUS, SLC_VARIABLE);
316 #else
317 defval(0);
318 #endif
320 case SLC_BRK:
321 case SLC_SYNCH:
322 case SLC_EOR:
323 defval(0);
325 default:
326 *valp = 0;
327 *valpp = 0;
328 return(SLC_NOSUPPORT);
332 #ifdef _CRAY
334 * getnpty()
336 * Return the number of pty's configured into the system.
339 getnpty()
341 #ifdef _SC_CRAY_NPTY
342 int numptys;
344 if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
345 return numptys;
346 else
347 #endif /* _SC_CRAY_NPTY */
348 return 128;
350 #endif /* CRAY */
353 * getpty()
355 * Allocate a pty. As a side effect, the external character
356 * array "line" contains the name of the slave side.
358 * Returns the file descriptor of the opened pty.
361 static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
362 char *line = Xline;
364 #ifdef _CRAY
365 char myline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
366 #endif /* CRAY */
368 #if !defined(HAVE_PTSNAME) && defined(STREAMSPTY)
369 static char *ptsname(int fd)
371 #ifdef HAVE_TTYNAME
372 return ttyname(fd);
373 #else
374 return NULL;
375 #endif
377 #endif
379 int getpty(int *ptynum)
381 #ifdef __osf__ /* XXX */
382 int master;
383 int slave;
384 if(openpty(&master, &slave, line, 0, 0) == 0){
385 close(slave);
386 return master;
388 return -1;
389 #else
390 #ifdef HAVE__GETPTY
391 int master, slave;
392 char *p;
393 p = _getpty(&master, O_RDWR, 0600, 1);
394 if(p == NULL)
395 return -1;
396 strlcpy(line, p, sizeof(Xline));
397 return master;
398 #else
400 int p;
401 char *cp, *p1, *p2;
402 int i;
403 #if SunOS == 40
404 int dummy;
405 #endif
406 #if __linux
407 int master;
408 int slave;
409 if(openpty(&master, &slave, line, 0, 0) == 0){
410 close(slave);
411 return master;
413 #else
414 #ifdef STREAMSPTY
415 char *clone[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm",
416 "/dev/ptym/clone", 0 };
418 char **q;
419 for(q=clone; *q; q++){
420 p=open(*q, O_RDWR);
421 if(p >= 0){
422 #ifdef HAVE_GRANTPT
423 grantpt(p);
424 #endif
425 #ifdef HAVE_UNLOCKPT
426 unlockpt(p);
427 #endif
428 strlcpy(line, ptsname(p), sizeof(Xline));
429 really_stream = 1;
430 return p;
433 #endif /* STREAMSPTY */
434 #ifndef _CRAY
436 #ifndef __hpux
437 snprintf(line, sizeof(Xline), "/dev/ptyXX");
438 p1 = &line[8];
439 p2 = &line[9];
440 #else
441 snprintf(line, sizeof(Xline), "/dev/ptym/ptyXX");
442 p1 = &line[13];
443 p2 = &line[14];
444 #endif
447 for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
448 struct stat stb;
450 *p1 = *cp;
451 *p2 = '0';
453 * This stat() check is just to keep us from
454 * looping through all 256 combinations if there
455 * aren't that many ptys available.
457 if (stat(line, &stb) < 0)
458 break;
459 for (i = 0; i < 16; i++) {
460 *p2 = "0123456789abcdef"[i];
461 p = open(line, O_RDWR);
462 if (p > 0) {
463 #ifndef __hpux
464 line[5] = 't';
465 #else
466 for (p1 = &line[8]; *p1; p1++)
467 *p1 = *(p1+1);
468 line[9] = 't';
469 #endif
470 chown(line, 0, 0);
471 chmod(line, 0600);
472 #if SunOS == 40
473 if (ioctl(p, TIOCGPGRP, &dummy) == 0
474 || errno != EIO) {
475 chmod(line, 0666);
476 close(p);
477 line[5] = 'p';
478 } else
479 #endif /* SunOS == 40 */
480 return(p);
484 #else /* CRAY */
485 extern lowpty, highpty;
486 struct stat sb;
488 for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {
489 snprintf(myline, sizeof(myline), "/dev/pty/%03d", *ptynum);
490 p = open(myline, 2);
491 if (p < 0)
492 continue;
493 snprintf(line, sizeof(Xline), "/dev/ttyp%03d", *ptynum);
495 * Here are some shenanigans to make sure that there
496 * are no listeners lurking on the line.
498 if(stat(line, &sb) < 0) {
499 close(p);
500 continue;
502 if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
503 chown(line, 0, 0);
504 chmod(line, 0600);
505 close(p);
506 p = open(myline, 2);
507 if (p < 0)
508 continue;
511 * Now it should be safe...check for accessability.
513 if (access(line, 6) == 0)
514 return(p);
515 else {
516 /* no tty side to pty so skip it */
517 close(p);
520 #endif /* CRAY */
521 #endif /* STREAMSPTY */
522 #endif /* OPENPTY */
523 return(-1);
524 #endif
529 tty_isecho(void)
531 return (termbuf.c_lflag & ECHO);
535 tty_flowmode(void)
537 return((termbuf.c_iflag & IXON) ? 1 : 0);
541 tty_restartany(void)
543 return((termbuf.c_iflag & IXANY) ? 1 : 0);
546 void
547 tty_setecho(int on)
549 if (on)
550 termbuf.c_lflag |= ECHO;
551 else
552 termbuf.c_lflag &= ~ECHO;
556 tty_israw(void)
558 return(!(termbuf.c_lflag & ICANON));
561 void
562 tty_binaryin(int on)
564 if (on) {
565 termbuf.c_iflag &= ~ISTRIP;
566 } else {
567 termbuf.c_iflag |= ISTRIP;
571 void
572 tty_binaryout(int on)
574 if (on) {
575 termbuf.c_cflag &= ~(CSIZE|PARENB);
576 termbuf.c_cflag |= CS8;
577 termbuf.c_oflag &= ~OPOST;
578 } else {
579 termbuf.c_cflag &= ~CSIZE;
580 termbuf.c_cflag |= CS7|PARENB;
581 termbuf.c_oflag |= OPOST;
586 tty_isbinaryin(void)
588 return(!(termbuf.c_iflag & ISTRIP));
592 tty_isbinaryout(void)
594 return(!(termbuf.c_oflag&OPOST));
599 tty_issofttab(void)
601 # ifdef OXTABS
602 return (termbuf.c_oflag & OXTABS);
603 # endif
604 # ifdef TABDLY
605 return ((termbuf.c_oflag & TABDLY) == TAB3);
606 # endif
609 void
610 tty_setsofttab(int on)
612 if (on) {
613 # ifdef OXTABS
614 termbuf.c_oflag |= OXTABS;
615 # endif
616 # ifdef TABDLY
617 termbuf.c_oflag &= ~TABDLY;
618 termbuf.c_oflag |= TAB3;
619 # endif
620 } else {
621 # ifdef OXTABS
622 termbuf.c_oflag &= ~OXTABS;
623 # endif
624 # ifdef TABDLY
625 termbuf.c_oflag &= ~TABDLY;
626 termbuf.c_oflag |= TAB0;
627 # endif
632 tty_islitecho(void)
634 # ifdef ECHOCTL
635 return (!(termbuf.c_lflag & ECHOCTL));
636 # endif
637 # ifdef TCTLECH
638 return (!(termbuf.c_lflag & TCTLECH));
639 # endif
640 # if !defined(ECHOCTL) && !defined(TCTLECH)
641 return (0); /* assumes ctl chars are echoed '^x' */
642 # endif
645 void
646 tty_setlitecho(int on)
648 # ifdef ECHOCTL
649 if (on)
650 termbuf.c_lflag &= ~ECHOCTL;
651 else
652 termbuf.c_lflag |= ECHOCTL;
653 # endif
654 # ifdef TCTLECH
655 if (on)
656 termbuf.c_lflag &= ~TCTLECH;
657 else
658 termbuf.c_lflag |= TCTLECH;
659 # endif
663 tty_iscrnl(void)
665 return (termbuf.c_iflag & ICRNL);
669 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
671 #if B4800 != 4800
672 #define DECODE_BAUD
673 #endif
675 #ifdef DECODE_BAUD
678 * A table of available terminal speeds
680 struct termspeeds {
681 int speed;
682 int value;
683 } termspeeds[] = {
684 { 0, B0 }, { 50, B50 }, { 75, B75 },
685 { 110, B110 }, { 134, B134 }, { 150, B150 },
686 { 200, B200 }, { 300, B300 }, { 600, B600 },
687 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
688 { 4800, B4800 },
689 #ifdef B7200
690 { 7200, B7200 },
691 #endif
692 { 9600, B9600 },
693 #ifdef B14400
694 { 14400, B14400 },
695 #endif
696 #ifdef B19200
697 { 19200, B19200 },
698 #endif
699 #ifdef B28800
700 { 28800, B28800 },
701 #endif
702 #ifdef B38400
703 { 38400, B38400 },
704 #endif
705 #ifdef B57600
706 { 57600, B57600 },
707 #endif
708 #ifdef B115200
709 { 115200, B115200 },
710 #endif
711 #ifdef B230400
712 { 230400, B230400 },
713 #endif
714 { -1, 0 }
716 #endif /* DECODE_BUAD */
718 void
719 tty_tspeed(int val)
721 #ifdef DECODE_BAUD
722 struct termspeeds *tp;
724 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
726 if (tp->speed == -1) /* back up to last valid value */
727 --tp;
728 cfsetospeed(&termbuf, tp->value);
729 #else /* DECODE_BUAD */
730 cfsetospeed(&termbuf, val);
731 #endif /* DECODE_BUAD */
734 void
735 tty_rspeed(int val)
737 #ifdef DECODE_BAUD
738 struct termspeeds *tp;
740 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
742 if (tp->speed == -1) /* back up to last valid value */
743 --tp;
744 cfsetispeed(&termbuf, tp->value);
745 #else /* DECODE_BAUD */
746 cfsetispeed(&termbuf, val);
747 #endif /* DECODE_BAUD */
750 #ifdef PARENT_DOES_UTMP
751 extern struct utmp wtmp;
752 extern char wtmpf[];
754 extern void utmp_sig_init (void);
755 extern void utmp_sig_reset (void);
756 extern void utmp_sig_wait (void);
757 extern void utmp_sig_notify (int);
758 # endif /* PARENT_DOES_UTMP */
760 #ifdef STREAMSPTY
762 /* I_FIND seems to live a life of its own */
763 static int my_find(int fd, char *module)
765 #if defined(I_FIND) && defined(I_LIST)
766 static int flag;
767 static struct str_list sl;
768 int n;
769 int i;
771 if(!flag){
772 n = ioctl(fd, I_LIST, 0);
773 if(n < 0){
774 perror("ioctl(fd, I_LIST, 0)");
775 return -1;
777 sl.sl_modlist=(struct str_mlist*)malloc(n * sizeof(struct str_mlist));
778 sl.sl_nmods = n;
779 n = ioctl(fd, I_LIST, &sl);
780 if(n < 0){
781 perror("ioctl(fd, I_LIST, n)");
782 return -1;
784 flag = 1;
787 for(i=0; i<sl.sl_nmods; i++)
788 if(!strcmp(sl.sl_modlist[i].l_name, module))
789 return 1;
790 #endif
791 return 0;
794 static void maybe_push_modules(int fd, char **modules)
796 char **p;
797 int err;
799 for(p=modules; *p; p++){
800 err = my_find(fd, *p);
801 if(err == 1)
802 break;
803 if(err < 0 && errno != EINVAL)
804 fatalperror(net, "my_find()");
805 /* module not pushed or does not exist */
807 /* p points to null or to an already pushed module, now push all
808 modules before this one */
810 for(p--; p >= modules; p--){
811 err = ioctl(fd, I_PUSH, *p);
812 if(err < 0 && errno != EINVAL)
813 fatalperror(net, "I_PUSH");
816 #endif
819 * getptyslave()
821 * Open the slave side of the pty, and do any initialization
822 * that is necessary. The return value is a file descriptor
823 * for the slave side.
825 void getptyslave(void)
827 int t = -1;
829 struct winsize ws;
831 * Opening the slave side may cause initilization of the
832 * kernel tty structure. We need remember the state of
833 * if linemode was turned on
834 * terminal window size
835 * terminal speed
836 * so that we can re-set them if we need to.
841 * Make sure that we don't have a controlling tty, and
842 * that we are the session (process group) leader.
845 #ifdef HAVE_SETSID
846 if(setsid()<0)
847 fatalperror(net, "setsid()");
848 #else
849 # ifdef TIOCNOTTY
850 t = open(_PATH_TTY, O_RDWR);
851 if (t >= 0) {
852 ioctl(t, TIOCNOTTY, (char *)0);
853 close(t);
855 # endif
856 #endif
858 # ifdef PARENT_DOES_UTMP
860 * Wait for our parent to get the utmp stuff to get done.
862 utmp_sig_wait();
863 # endif
865 t = cleanopen(line);
866 if (t < 0)
867 fatalperror(net, line);
869 #ifdef STREAMSPTY
870 ttyfd = t;
874 * Not all systems have (or need) modules ttcompat and pckt so
875 * don't flag it as a fatal error if they don't exist.
878 if (really_stream)
880 /* these are the streams modules that we want pushed. note
881 that they are in reverse order, ptem will be pushed
882 first. maybe_push_modules() will try to push all modules
883 before the first one that isn't already pushed. i.e if
884 ldterm is pushed, only ttcompat will be attempted.
886 all this is because we don't know which modules are
887 available, and we don't know which modules are already
888 pushed (via autopush, for instance).
892 char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL };
893 char *ptymodules[] = { "pckt", NULL };
895 maybe_push_modules(t, ttymodules);
896 maybe_push_modules(ourpty, ptymodules);
898 #endif
900 * set up the tty modes as we like them to be.
902 init_termbuf();
903 # ifdef TIOCSWINSZ
904 if (def_row || def_col) {
905 memset(&ws, 0, sizeof(ws));
906 ws.ws_col = def_col;
907 ws.ws_row = def_row;
908 ioctl(t, TIOCSWINSZ, (char *)&ws);
910 # endif
913 * Settings for sgtty based systems
917 * Settings for UNICOS (and HPUX)
919 # if defined(_CRAY) || defined(__hpux)
920 termbuf.c_oflag = OPOST|ONLCR|TAB3;
921 termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
922 termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
923 termbuf.c_cflag = EXTB|HUPCL|CS8;
924 # endif
927 * Settings for all other termios/termio based
928 * systems, other than 4.4BSD. In 4.4BSD the
929 * kernel does the initial terminal setup.
931 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43)
932 # ifndef OXTABS
933 # define OXTABS 0
934 # endif
935 termbuf.c_lflag |= ECHO;
936 termbuf.c_oflag |= ONLCR|OXTABS;
937 termbuf.c_iflag |= ICRNL;
938 termbuf.c_iflag &= ~IXOFF;
939 # endif
940 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
941 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
944 * Set the tty modes, and make this our controlling tty.
946 set_termbuf();
947 if (login_tty(t) == -1)
948 fatalperror(net, "login_tty");
949 if (net > 2)
950 close(net);
951 if (ourpty > 2) {
952 close(ourpty);
953 ourpty = -1;
957 #ifndef O_NOCTTY
958 #define O_NOCTTY 0
959 #endif
961 * Open the specified slave side of the pty,
962 * making sure that we have a clean tty.
965 int cleanopen(char *line)
967 int t;
969 #ifdef STREAMSPTY
970 if (!really_stream)
971 #endif
974 * Make sure that other people can't open the
975 * slave side of the connection.
977 chown(line, 0, 0);
978 chmod(line, 0600);
981 #ifdef HAVE_REVOKE
982 revoke(line);
983 #endif
985 t = open(line, O_RDWR|O_NOCTTY);
987 if (t < 0)
988 return(-1);
991 * Hangup anybody else using this ttyp, then reopen it for
992 * ourselves.
994 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
995 signal(SIGHUP, SIG_IGN);
996 #ifdef HAVE_VHANGUP
997 vhangup();
998 #else
999 #endif
1000 signal(SIGHUP, SIG_DFL);
1001 t = open(line, O_RDWR|O_NOCTTY);
1002 if (t < 0)
1003 return(-1);
1004 # endif
1005 # if defined(_CRAY) && defined(TCVHUP)
1007 int i;
1008 signal(SIGHUP, SIG_IGN);
1009 ioctl(t, TCVHUP, (char *)0);
1010 signal(SIGHUP, SIG_DFL);
1012 i = open(line, O_RDWR);
1014 if (i < 0)
1015 return(-1);
1016 close(t);
1017 t = i;
1019 # endif /* defined(CRAY) && defined(TCVHUP) */
1020 return(t);
1023 #if !defined(BSD4_4)
1025 int login_tty(int t)
1027 # if defined(TIOCSCTTY) && !defined(__hpux)
1028 if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
1029 fatalperror(net, "ioctl(sctty)");
1030 # ifdef _CRAY
1032 * Close the hard fd to /dev/ttypXXX, and re-open through
1033 * the indirect /dev/tty interface.
1035 close(t);
1036 if ((t = open("/dev/tty", O_RDWR)) < 0)
1037 fatalperror(net, "open(/dev/tty)");
1038 # endif
1039 # else
1041 * We get our controlling tty assigned as a side-effect
1042 * of opening up a tty device. But on BSD based systems,
1043 * this only happens if our process group is zero. The
1044 * setsid() call above may have set our pgrp, so clear
1045 * it out before opening the tty...
1047 #ifdef HAVE_SETPGID
1048 setpgid(0, 0);
1049 #else
1050 setpgrp(0, 0); /* if setpgid isn't available, setpgrp
1051 probably takes arguments */
1052 #endif
1053 close(open(line, O_RDWR));
1054 # endif
1055 if (t != 0)
1056 dup2(t, 0);
1057 if (t != 1)
1058 dup2(t, 1);
1059 if (t != 2)
1060 dup2(t, 2);
1061 if (t > 2)
1062 close(t);
1063 return(0);
1065 #endif /* BSD <= 43 */
1068 * This comes from ../../bsd/tty.c and should not really be here.
1072 * Clean the tty name. Return a pointer to the cleaned version.
1075 static char *
1076 clean_ttyname (char *tty)
1078 char *res = tty;
1080 if (strncmp (res, _PATH_DEV, strlen(_PATH_DEV)) == 0)
1081 res += strlen(_PATH_DEV);
1082 if (strncmp (res, "pty/", 4) == 0)
1083 res += 4;
1084 if (strncmp (res, "ptym/", 5) == 0)
1085 res += 5;
1086 return res;
1090 * Generate a name usable as an `ut_id', typically without `tty'.
1093 #ifdef HAVE_STRUCT_UTMP_UT_ID
1094 static char *
1095 make_id (char *tty)
1097 char *res = tty;
1099 if (strncmp (res, "pts/", 4) == 0)
1100 res += 4;
1101 if (strncmp (res, "tty", 3) == 0)
1102 res += 3;
1103 return res;
1105 #endif
1108 * startslave(host)
1110 * Given a hostname, do whatever
1111 * is necessary to startup the login process on the slave side of the pty.
1114 /* ARGSUSED */
1115 void
1116 startslave(const char *host, const char *utmp_host,
1117 int autologin, char *autoname)
1119 int i;
1121 #ifdef AUTHENTICATION
1122 if (!autoname || !autoname[0])
1123 autologin = 0;
1125 if (autologin < auth_level) {
1126 fatal(net, "Authorization failed");
1127 exit(1);
1129 #endif
1132 char *tbuf =
1133 "\r\n*** Connection not encrypted! "
1134 "Communication may be eavesdropped. ***\r\n";
1135 #ifdef ENCRYPTION
1136 if (!no_warn && (encrypt_output == 0 || decrypt_input == 0))
1137 #endif
1138 writenet((unsigned char*)tbuf, strlen(tbuf));
1140 # ifdef PARENT_DOES_UTMP
1141 utmp_sig_init();
1142 # endif /* PARENT_DOES_UTMP */
1144 if ((i = fork()) < 0)
1145 fatalperror(net, "fork");
1146 if (i) {
1147 # ifdef PARENT_DOES_UTMP
1149 * Cray parent will create utmp entry for child and send
1150 * signal to child to tell when done. Child waits for signal
1151 * before doing anything important.
1153 int pid = i;
1154 void sigjob (int);
1156 setpgrp();
1157 utmp_sig_reset(); /* reset handler to default */
1159 * Create utmp entry for child
1161 wtmp.ut_time = time(NULL);
1162 wtmp.ut_type = LOGIN_PROCESS;
1163 wtmp.ut_pid = pid;
1164 strncpy(wtmp.ut_user, "LOGIN", sizeof(wtmp.ut_user));
1165 strncpy(wtmp.ut_host, utmp_host, sizeof(wtmp.ut_host));
1166 strncpy(wtmp.ut_line, clean_ttyname(line), sizeof(wtmp.ut_line));
1167 #ifdef HAVE_STRUCT_UTMP_UT_ID
1168 strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id));
1169 #endif
1171 pututline(&wtmp);
1172 endutent();
1173 if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
1174 write(i, &wtmp, sizeof(struct utmp));
1175 close(i);
1177 #ifdef _CRAY
1178 signal(WJSIGNAL, sigjob);
1179 #endif
1180 utmp_sig_notify(pid);
1181 # endif /* PARENT_DOES_UTMP */
1182 } else {
1183 getptyslave();
1184 #if defined(DCE)
1185 /* if we authenticated via K5, try and join the PAG */
1186 kerberos5_dfspag();
1187 #endif
1188 start_login(host, autologin, autoname);
1189 /*NOTREACHED*/
1193 char *envinit[3];
1194 extern char **environ;
1196 void
1197 init_env(void)
1199 char **envp;
1201 envp = envinit;
1202 if ((*envp = getenv("TZ")))
1203 *envp++ -= 3;
1204 #if defined(_CRAY) || defined(__hpux)
1205 else
1206 *envp++ = "TZ=GMT0";
1207 #endif
1208 *envp = 0;
1209 environ = envinit;
1213 * scrub_env()
1215 * We only accept the environment variables listed below.
1218 static void
1219 scrub_env(void)
1221 static const char *reject[] = {
1222 "TERMCAP=/",
1223 NULL
1226 static const char *accept[] = {
1227 "XAUTH=", "XAUTHORITY=", "DISPLAY=",
1228 "TERM=",
1229 "EDITOR=",
1230 "PAGER=",
1231 "PRINTER=",
1232 "LOGNAME=",
1233 "POSIXLY_CORRECT=",
1234 "TERMCAP=",
1235 NULL
1238 char **cpp, **cpp2;
1239 const char **p;
1240 char ** new_environ;
1241 size_t count;
1243 /* Allocate space for scrubbed environment. */
1244 for (count = 1, cpp = environ; *cpp; count++, cpp++)
1246 if ((new_environ = malloc(count * sizeof(char *))) == NULL) {
1247 environ = NULL;
1248 return;
1251 for (cpp2 = new_environ, cpp = environ; *cpp; cpp++) {
1252 int reject_it = 0;
1254 for(p = reject; *p; p++)
1255 if(strncmp(*cpp, *p, strlen(*p)) == 0) {
1256 reject_it = 1;
1257 break;
1259 if (reject_it)
1260 continue;
1262 for(p = accept; *p; p++)
1263 if(strncmp(*cpp, *p, strlen(*p)) == 0)
1264 break;
1265 if(*p != NULL) {
1266 if ((*cpp2++ = strdup(*cpp)) == NULL) {
1267 environ = new_environ;
1268 return;
1272 *cpp2 = NULL;
1273 environ = new_environ;
1277 struct arg_val {
1278 int size;
1279 int argc;
1280 const char **argv;
1283 static void addarg(struct arg_val*, const char*);
1286 * start_login(host)
1288 * Assuming that we are now running as a child processes, this
1289 * function will turn us into the login process.
1292 void
1293 start_login(const char *host, int autologin, char *name)
1295 struct arg_val argv;
1296 char *user;
1297 int save_errno;
1299 #ifdef HAVE_UTMPX_H
1300 int pid = getpid();
1301 struct utmpx utmpx;
1302 char *clean_tty;
1305 * Create utmp entry for child
1308 clean_tty = clean_ttyname(line);
1309 memset(&utmpx, 0, sizeof(utmpx));
1310 strncpy(utmpx.ut_user, ".telnet", sizeof(utmpx.ut_user));
1311 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1312 #ifdef HAVE_STRUCT_UTMP_UT_ID
1313 strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id));
1314 #endif
1315 utmpx.ut_pid = pid;
1317 utmpx.ut_type = LOGIN_PROCESS;
1319 gettimeofday (&utmpx.ut_tv, NULL);
1320 if (pututxline(&utmpx) == NULL)
1321 fatal(net, "pututxline failed");
1322 #endif
1324 scrub_env();
1327 * -h : pass on name of host.
1328 * WARNING: -h is accepted by login if and only if
1329 * getuid() == 0.
1330 * -p : don't clobber the environment (so terminal type stays set).
1332 * -f : force this login, he has already been authenticated
1335 /* init argv structure */
1336 argv.size=0;
1337 argv.argc=0;
1338 argv.argv=malloc(0); /*so we can call realloc later */
1339 addarg(&argv, "login");
1340 addarg(&argv, "-h");
1341 addarg(&argv, host);
1342 addarg(&argv, "-p");
1343 if(name[0])
1344 user = name;
1345 else
1346 user = getenv("USER");
1347 #ifdef AUTHENTICATION
1348 if (auth_level < 0 || autologin != AUTH_VALID) {
1349 if(!no_warn) {
1350 printf("User not authenticated. ");
1351 if (require_otp)
1352 printf("Using one-time password\r\n");
1353 else
1354 printf("Using plaintext username and password\r\n");
1356 if (require_otp) {
1357 addarg(&argv, "-a");
1358 addarg(&argv, "otp");
1360 if(log_unauth)
1361 syslog(LOG_INFO, "unauthenticated access from %s (%s)",
1362 host, user ? user : "unknown user");
1364 if (auth_level >= 0 && autologin == AUTH_VALID)
1365 addarg(&argv, "-f");
1366 #endif
1367 if(user){
1368 addarg(&argv, "--");
1369 addarg(&argv, strdup(user));
1371 if (getenv("USER")) {
1373 * Assume that login will set the USER variable
1374 * correctly. For SysV systems, this means that
1375 * USER will no longer be set, just LOGNAME by
1376 * login. (The problem is that if the auto-login
1377 * fails, and the user then specifies a different
1378 * account name, he can get logged in with both
1379 * LOGNAME and USER in his environment, but the
1380 * USER value will be wrong.
1382 unsetenv("USER");
1384 closelog();
1386 * This sleep(1) is in here so that telnetd can
1387 * finish up with the tty. There's a race condition
1388 * the login banner message gets lost...
1390 sleep(1);
1392 execv(new_login, argv.argv);
1393 save_errno = errno;
1394 syslog(LOG_ERR, "%s: %m\n", new_login);
1395 fatalperror_errno(net, new_login, save_errno);
1396 /*NOTREACHED*/
1399 static void
1400 addarg(struct arg_val *argv, const char *val)
1402 if(argv->size <= argv->argc+1) {
1403 argv->argv = realloc(argv->argv, sizeof(char*) * (argv->size + 10));
1404 if (argv->argv == NULL)
1405 fatal (net, "realloc: out of memory");
1406 argv->size+=10;
1408 argv->argv[argv->argc++] = val;
1409 argv->argv[argv->argc] = NULL;
1414 * rmut()
1416 * This is the function called by cleanup() to
1417 * remove the utmp entry for this person.
1420 #ifdef HAVE_UTMPX_H
1421 static void
1422 rmut(void)
1424 struct utmpx utmpx, *non_save_utxp;
1425 char *clean_tty = clean_ttyname(line);
1428 * This updates the utmpx and utmp entries and make a wtmp/x entry
1431 setutxent();
1432 memset(&utmpx, 0, sizeof(utmpx));
1433 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1434 utmpx.ut_type = LOGIN_PROCESS;
1435 non_save_utxp = getutxline(&utmpx);
1436 if (non_save_utxp) {
1437 struct utmpx *utxp;
1438 char user0;
1440 utxp = malloc(sizeof(struct utmpx));
1441 *utxp = *non_save_utxp;
1442 user0 = utxp->ut_user[0];
1443 utxp->ut_user[0] = '\0';
1444 utxp->ut_type = DEAD_PROCESS;
1445 #ifdef HAVE_STRUCT_UTMPX_UT_EXIT
1446 #ifdef _STRUCT___EXIT_STATUS
1447 utxp->ut_exit.__e_termination = 0;
1448 utxp->ut_exit.__e_exit = 0;
1449 #elif defined(__osf__) /* XXX */
1450 utxp->ut_exit.ut_termination = 0;
1451 utxp->ut_exit.ut_exit = 0;
1452 #else
1453 utxp->ut_exit.e_termination = 0;
1454 utxp->ut_exit.e_exit = 0;
1455 #endif
1456 #endif
1457 gettimeofday(&utxp->ut_tv, NULL);
1458 pututxline(utxp);
1459 #ifdef WTMPX_FILE
1460 utxp->ut_user[0] = user0;
1461 updwtmpx(WTMPX_FILE, utxp);
1462 #elif defined(WTMP_FILE)
1463 /* This is a strange system with a utmpx and a wtmp! */
1465 int f = open(wtmpf, O_WRONLY|O_APPEND);
1466 struct utmp wtmp;
1467 if (f >= 0) {
1468 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));
1469 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));
1470 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1471 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));
1472 #endif
1473 wtmp.ut_time = time(NULL);
1474 write(f, &wtmp, sizeof(wtmp));
1475 close(f);
1478 #endif
1479 free (utxp);
1481 endutxent();
1482 } /* end of rmut */
1483 #endif
1485 #if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43
1486 static void
1487 rmut(void)
1489 int f;
1490 int found = 0;
1491 struct utmp *u, *utmp;
1492 int nutmp;
1493 struct stat statbf;
1494 char *clean_tty = clean_ttyname(line);
1496 f = open(utmpf, O_RDWR);
1497 if (f >= 0) {
1498 fstat(f, &statbf);
1499 utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
1500 if (!utmp)
1501 syslog(LOG_ERR, "utmp malloc failed");
1502 if (statbf.st_size && utmp) {
1503 nutmp = read(f, utmp, (int)statbf.st_size);
1504 nutmp /= sizeof(struct utmp);
1506 for (u = utmp ; u < &utmp[nutmp] ; u++) {
1507 if (strncmp(u->ut_line,
1508 clean_tty,
1509 sizeof(u->ut_line)) ||
1510 u->ut_name[0]==0)
1511 continue;
1512 lseek(f, ((long)u)-((long)utmp), L_SET);
1513 strncpy(u->ut_name, "", sizeof(u->ut_name));
1514 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1515 strncpy(u->ut_host, "", sizeof(u->ut_host));
1516 #endif
1517 u->ut_time = time(NULL);
1518 write(f, u, sizeof(wtmp));
1519 found++;
1522 close(f);
1524 if (found) {
1525 f = open(wtmpf, O_WRONLY|O_APPEND);
1526 if (f >= 0) {
1527 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));
1528 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));
1529 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1530 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));
1531 #endif
1532 wtmp.ut_time = time(NULL);
1533 write(f, &wtmp, sizeof(wtmp));
1534 close(f);
1537 chmod(line, 0666);
1538 chown(line, 0, 0);
1539 line[strlen("/dev/")] = 'p';
1540 chmod(line, 0666);
1541 chown(line, 0, 0);
1542 } /* end of rmut */
1543 #endif /* CRAY */
1545 #if defined(__hpux) && !defined(HAVE_UTMPX_H)
1546 static void
1547 rmut (char *line)
1549 struct utmp utmp;
1550 struct utmp *utptr;
1551 int fd; /* for /etc/wtmp */
1553 utmp.ut_type = USER_PROCESS;
1554 strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line));
1555 setutent();
1556 utptr = getutline(&utmp);
1557 /* write it out only if it exists */
1558 if (utptr) {
1559 utptr->ut_type = DEAD_PROCESS;
1560 utptr->ut_time = time(NULL);
1561 pututline(utptr);
1562 /* set wtmp entry if wtmp file exists */
1563 if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
1564 write(fd, utptr, sizeof(utmp));
1565 close(fd);
1568 endutent();
1570 chmod(line, 0666);
1571 chown(line, 0, 0);
1572 line[14] = line[13];
1573 line[13] = line[12];
1574 line[8] = 'm';
1575 line[9] = '/';
1576 line[10] = 'p';
1577 line[11] = 't';
1578 line[12] = 'y';
1579 chmod(line, 0666);
1580 chown(line, 0, 0);
1582 #endif
1585 * cleanup()
1587 * This is the routine to call when we are all through, to
1588 * clean up anything that needs to be cleaned up.
1591 #ifdef PARENT_DOES_UTMP
1593 void
1594 cleanup(int sig)
1596 #ifdef _CRAY
1597 static int incleanup = 0;
1598 int t;
1599 int child_status; /* status of child process as returned by waitpid */
1600 int flags = WNOHANG|WUNTRACED;
1603 * 1: Pick up the zombie, if we are being called
1604 * as the signal handler.
1605 * 2: If we are a nested cleanup(), return.
1606 * 3: Try to clean up TMPDIR.
1607 * 4: Fill in utmp with shutdown of process.
1608 * 5: Close down the network and pty connections.
1609 * 6: Finish up the TMPDIR cleanup, if needed.
1611 if (sig == SIGCHLD) {
1612 while (waitpid(-1, &child_status, flags) > 0)
1613 ; /* VOID */
1614 /* Check if the child process was stopped
1615 * rather than exited. We want cleanup only if
1616 * the child has died.
1618 if (WIFSTOPPED(child_status)) {
1619 return;
1622 t = sigblock(sigmask(SIGCHLD));
1623 if (incleanup) {
1624 sigsetmask(t);
1625 return;
1627 incleanup = 1;
1628 sigsetmask(t);
1630 t = cleantmp(&wtmp);
1631 setutent(); /* just to make sure */
1632 #endif /* CRAY */
1633 rmut(line);
1634 close(ourpty);
1635 shutdown(net, 2);
1636 #ifdef _CRAY
1637 if (t == 0)
1638 cleantmp(&wtmp);
1639 #endif /* CRAY */
1640 exit(1);
1643 #else /* PARENT_DOES_UTMP */
1645 void
1646 cleanup(int sig)
1648 #if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)
1649 rmut();
1650 #ifdef HAVE_VHANGUP
1651 #ifndef __sgi
1652 vhangup(); /* XXX */
1653 #endif
1654 #endif
1655 #else
1656 char *p;
1658 p = line + sizeof("/dev/") - 1;
1659 if (logout(p))
1660 logwtmp(p, "", "");
1661 chmod(line, 0666);
1662 chown(line, 0, 0);
1663 *p = 'p';
1664 chmod(line, 0666);
1665 chown(line, 0, 0);
1666 #endif
1667 shutdown(net, 2);
1668 exit(1);
1671 #endif /* PARENT_DOES_UTMP */
1673 #ifdef PARENT_DOES_UTMP
1675 * _utmp_sig_rcv
1676 * utmp_sig_init
1677 * utmp_sig_wait
1678 * These three functions are used to coordinate the handling of
1679 * the utmp file between the server and the soon-to-be-login shell.
1680 * The server actually creates the utmp structure, the child calls
1681 * utmp_sig_wait(), until the server calls utmp_sig_notify() and
1682 * signals the future-login shell to proceed.
1684 static int caught=0; /* NZ when signal intercepted */
1685 static void (*func)(); /* address of previous handler */
1687 void
1688 _utmp_sig_rcv(sig)
1689 int sig;
1691 caught = 1;
1692 signal(SIGUSR1, func);
1695 void
1696 utmp_sig_init()
1699 * register signal handler for UTMP creation
1701 if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1702 fatalperror(net, "telnetd/signal");
1705 void
1706 utmp_sig_reset()
1708 signal(SIGUSR1, func); /* reset handler to default */
1711 # ifdef __hpux
1712 # define sigoff() /* do nothing */
1713 # define sigon() /* do nothing */
1714 # endif
1716 void
1717 utmp_sig_wait()
1720 * Wait for parent to write our utmp entry.
1722 sigoff();
1723 while (caught == 0) {
1724 pause(); /* wait until we get a signal (sigon) */
1725 sigoff(); /* turn off signals while we check caught */
1727 sigon(); /* turn on signals again */
1730 void
1731 utmp_sig_notify(pid)
1733 kill(pid, SIGUSR1);
1736 #ifdef _CRAY
1737 static int gotsigjob = 0;
1739 /*ARGSUSED*/
1740 void
1741 sigjob(sig)
1742 int sig;
1744 int jid;
1745 struct jobtemp *jp;
1747 while ((jid = waitjob(NULL)) != -1) {
1748 if (jid == 0) {
1749 return;
1751 gotsigjob++;
1752 jobend(jid, NULL, NULL);
1757 * jid_getutid:
1758 * called by jobend() before calling cleantmp()
1759 * to find the correct $TMPDIR to cleanup.
1762 struct utmp *
1763 jid_getutid(jid)
1764 int jid;
1766 struct utmp *cur = NULL;
1768 setutent(); /* just to make sure */
1769 while (cur = getutent()) {
1770 if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
1771 return(cur);
1775 return(0);
1779 * Clean up the TMPDIR that login created.
1780 * The first time this is called we pick up the info
1781 * from the utmp. If the job has already gone away,
1782 * then we'll clean up and be done. If not, then
1783 * when this is called the second time it will wait
1784 * for the signal that the job is done.
1787 cleantmp(wtp)
1788 struct utmp *wtp;
1790 struct utmp *utp;
1791 static int first = 1;
1792 int mask, omask, ret;
1793 extern struct utmp *getutid (const struct utmp *_Id);
1796 mask = sigmask(WJSIGNAL);
1798 if (first == 0) {
1799 omask = sigblock(mask);
1800 while (gotsigjob == 0)
1801 sigpause(omask);
1802 return(1);
1804 first = 0;
1805 setutent(); /* just to make sure */
1807 utp = getutid(wtp);
1808 if (utp == 0) {
1809 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1810 return(-1);
1813 * Nothing to clean up if the user shell was never started.
1815 if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
1816 return(1);
1819 * Block the WJSIGNAL while we are in jobend().
1821 omask = sigblock(mask);
1822 ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
1823 sigsetmask(omask);
1824 return(ret);
1828 jobend(jid, path, user)
1829 int jid;
1830 char *path;
1831 char *user;
1833 static int saved_jid = 0;
1834 static int pty_saved_jid = 0;
1835 static char saved_path[sizeof(wtmp.ut_tpath)+1];
1836 static char saved_user[sizeof(wtmp.ut_user)+1];
1839 * this little piece of code comes into play
1840 * only when ptyreconnect is used to reconnect
1841 * to an previous session.
1843 * this is the only time when the
1844 * "saved_jid != jid" code is executed.
1847 if ( saved_jid && saved_jid != jid ) {
1848 if (!path) { /* called from signal handler */
1849 pty_saved_jid = jid;
1850 } else {
1851 pty_saved_jid = saved_jid;
1855 if (path) {
1856 strncpy(saved_path, path, sizeof(wtmp.ut_tpath));
1857 strncpy(saved_user, user, sizeof(wtmp.ut_user));
1858 saved_path[sizeof(saved_path)] = '\0';
1859 saved_user[sizeof(saved_user)] = '\0';
1861 if (saved_jid == 0) {
1862 saved_jid = jid;
1863 return(0);
1866 /* if the jid has changed, get the correct entry from the utmp file */
1868 if ( saved_jid != jid ) {
1869 struct utmp *utp = NULL;
1870 struct utmp *jid_getutid();
1872 utp = jid_getutid(pty_saved_jid);
1874 if (utp == 0) {
1875 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1876 return(-1);
1879 cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
1880 return(1);
1883 cleantmpdir(jid, saved_path, saved_user);
1884 return(1);
1888 * Fork a child process to clean up the TMPDIR
1890 cleantmpdir(jid, tpath, user)
1891 int jid;
1892 char *tpath;
1893 char *user;
1895 switch(fork()) {
1896 case -1:
1897 syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
1898 tpath);
1899 break;
1900 case 0:
1901 execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0);
1902 syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1903 tpath, CLEANTMPCMD);
1904 exit(1);
1905 default:
1907 * Forget about child. We will exit, and
1908 * /etc/init will pick it up.
1910 break;
1913 #endif /* CRAY */
1914 #endif /* defined(PARENT_DOES_UTMP) */