fix
[heimdal.git] / appl / telnet / telnetd / sys_term.c
blobea357a862ba7832ba3846b2562645ddb97d44970
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$");
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 #ifdef HAVE_SYS_STREAM_H
106 #ifdef HAVE_SYS_UIO_H
107 #include <sys/uio.h>
108 #endif
109 #ifdef __hpux
110 #undef SE
111 #endif
112 #include <sys/stream.h>
113 #endif
114 #if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY)
115 #include <sys/tty.h>
116 #endif
117 #ifdef t_erase
118 #undef t_erase
119 #undef t_kill
120 #undef t_intrc
121 #undef t_quitc
122 #undef t_startc
123 #undef t_stopc
124 #undef t_eofc
125 #undef t_brkc
126 #undef t_suspc
127 #undef t_dsuspc
128 #undef t_rprntc
129 #undef t_flushc
130 #undef t_werasc
131 #undef t_lnextc
132 #endif
134 #ifdef HAVE_TERMIOS_H
135 #include <termios.h>
136 #else
137 #ifdef HAVE_TERMIO_H
138 #include <termio.h>
139 #endif
140 #endif
142 #ifdef HAVE_UTIL_H
143 #include <util.h>
144 #endif
146 # ifndef TCSANOW
147 # ifdef TCSETS
148 # define TCSANOW TCSETS
149 # define TCSADRAIN TCSETSW
150 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
151 # else
152 # ifdef TCSETA
153 # define TCSANOW TCSETA
154 # define TCSADRAIN TCSETAW
155 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
156 # else
157 # define TCSANOW TIOCSETA
158 # define TCSADRAIN TIOCSETAW
159 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
160 # endif
161 # endif
162 # define tcsetattr(f, a, t) ioctl(f, a, t)
163 # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
164 (tp)->c_cflag |= (val)
165 # define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
166 # ifdef CIBAUD
167 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
168 (tp)->c_cflag |= ((val)<<IBSHIFT)
169 # define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
170 # else
171 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
172 (tp)->c_cflag |= (val)
173 # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
174 # endif
175 # endif /* TCSANOW */
176 struct termios termbuf, termbuf2; /* pty control structure */
177 # ifdef STREAMSPTY
178 static int ttyfd = -1;
179 int really_stream = 0;
180 # endif
182 const char *new_login = _PATH_LOGIN;
185 * init_termbuf()
186 * copy_termbuf(cp)
187 * set_termbuf()
189 * These three routines are used to get and set the "termbuf" structure
190 * to and from the kernel. init_termbuf() gets the current settings.
191 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
192 * set_termbuf() writes the structure into the kernel.
195 void
196 init_termbuf(void)
198 # ifdef STREAMSPTY
199 if (really_stream)
200 tcgetattr(ttyfd, &termbuf);
201 else
202 # endif
203 tcgetattr(ourpty, &termbuf);
204 termbuf2 = termbuf;
207 void
208 set_termbuf(void)
211 * Only make the necessary changes.
213 if (memcmp(&termbuf, &termbuf2, sizeof(termbuf)))
214 # ifdef STREAMSPTY
215 if (really_stream)
216 tcsetattr(ttyfd, TCSANOW, &termbuf);
217 else
218 # endif
219 tcsetattr(ourpty, TCSANOW, &termbuf);
224 * spcset(func, valp, valpp)
226 * This function takes various special characters (func), and
227 * sets *valp to the current value of that character, and
228 * *valpp to point to where in the "termbuf" structure that
229 * value is kept.
231 * It returns the SLC_ level of support for this function.
236 spcset(int func, cc_t *valp, cc_t **valpp)
239 #define setval(a, b) *valp = termbuf.c_cc[a]; \
240 *valpp = &termbuf.c_cc[a]; \
241 return(b);
242 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
244 switch(func) {
245 case SLC_EOF:
246 setval(VEOF, SLC_VARIABLE);
247 case SLC_EC:
248 setval(VERASE, SLC_VARIABLE);
249 case SLC_EL:
250 setval(VKILL, SLC_VARIABLE);
251 case SLC_IP:
252 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
253 case SLC_ABORT:
254 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
255 case SLC_XON:
256 #ifdef VSTART
257 setval(VSTART, SLC_VARIABLE);
258 #else
259 defval(0x13);
260 #endif
261 case SLC_XOFF:
262 #ifdef VSTOP
263 setval(VSTOP, SLC_VARIABLE);
264 #else
265 defval(0x11);
266 #endif
267 case SLC_EW:
268 #ifdef VWERASE
269 setval(VWERASE, SLC_VARIABLE);
270 #else
271 defval(0);
272 #endif
273 case SLC_RP:
274 #ifdef VREPRINT
275 setval(VREPRINT, SLC_VARIABLE);
276 #else
277 defval(0);
278 #endif
279 case SLC_LNEXT:
280 #ifdef VLNEXT
281 setval(VLNEXT, SLC_VARIABLE);
282 #else
283 defval(0);
284 #endif
285 case SLC_AO:
286 #if !defined(VDISCARD) && defined(VFLUSHO)
287 # define VDISCARD VFLUSHO
288 #endif
289 #ifdef VDISCARD
290 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
291 #else
292 defval(0);
293 #endif
294 case SLC_SUSP:
295 #ifdef VSUSP
296 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
297 #else
298 defval(0);
299 #endif
300 #ifdef VEOL
301 case SLC_FORW1:
302 setval(VEOL, SLC_VARIABLE);
303 #endif
304 #ifdef VEOL2
305 case SLC_FORW2:
306 setval(VEOL2, SLC_VARIABLE);
307 #endif
308 case SLC_AYT:
309 #ifdef VSTATUS
310 setval(VSTATUS, SLC_VARIABLE);
311 #else
312 defval(0);
313 #endif
315 case SLC_BRK:
316 case SLC_SYNCH:
317 case SLC_EOR:
318 defval(0);
320 default:
321 *valp = 0;
322 *valpp = 0;
323 return(SLC_NOSUPPORT);
327 #ifdef _CRAY
329 * getnpty()
331 * Return the number of pty's configured into the system.
334 getnpty()
336 #ifdef _SC_CRAY_NPTY
337 int numptys;
339 if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
340 return numptys;
341 else
342 #endif /* _SC_CRAY_NPTY */
343 return 128;
345 #endif /* CRAY */
348 * getpty()
350 * Allocate a pty. As a side effect, the external character
351 * array "line" contains the name of the slave side.
353 * Returns the file descriptor of the opened pty.
356 static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
357 char *line = Xline;
359 #ifdef _CRAY
360 char myline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
361 #endif /* CRAY */
363 #if !defined(HAVE_PTSNAME) && defined(STREAMSPTY)
364 static char *ptsname(int fd)
366 #ifdef HAVE_TTYNAME
367 return ttyname(fd);
368 #else
369 return NULL;
370 #endif
372 #endif
374 int getpty(int *ptynum)
376 #ifdef __osf__ /* XXX */
377 int master;
378 int slave;
379 if(openpty(&master, &slave, line, 0, 0) == 0){
380 close(slave);
381 return master;
383 return -1;
384 #else
385 #ifdef HAVE__GETPTY
386 int master, slave;
387 char *p;
388 p = _getpty(&master, O_RDWR, 0600, 1);
389 if(p == NULL)
390 return -1;
391 strcpy_truncate(line, p, sizeof(Xline));
392 return master;
393 #else
395 int p;
396 char *cp, *p1, *p2;
397 int i;
398 #if SunOS == 4
399 int dummy;
400 #endif
401 #if 0 /* && defined(HAVE_OPENPTY) */
402 int master;
403 int slave;
404 if(openpty(&master, &slave, line, 0, 0) == 0){
405 close(slave);
406 return master;
408 #else
409 #ifdef STREAMSPTY
410 char *clone[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm",
411 "/dev/ptym/clone", 0 };
413 char **q;
414 for(q=clone; *q; q++){
415 p=open(*q, O_RDWR);
416 if(p >= 0){
417 #ifdef HAVE_GRANTPT
418 grantpt(p);
419 #endif
420 #ifdef HAVE_UNLOCKPT
421 unlockpt(p);
422 #endif
423 strcpy_truncate(line, ptsname(p), sizeof(Xline));
424 really_stream = 1;
425 return p;
428 #endif /* STREAMSPTY */
429 #ifndef _CRAY
431 #ifndef __hpux
432 snprintf(line, sizeof(Xline), "/dev/ptyXX");
433 p1 = &line[8];
434 p2 = &line[9];
435 #else
436 snprintf(line, sizeof(Xline), "/dev/ptym/ptyXX");
437 p1 = &line[13];
438 p2 = &line[14];
439 #endif
442 for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
443 struct stat stb;
445 *p1 = *cp;
446 *p2 = '0';
448 * This stat() check is just to keep us from
449 * looping through all 256 combinations if there
450 * aren't that many ptys available.
452 if (stat(line, &stb) < 0)
453 break;
454 for (i = 0; i < 16; i++) {
455 *p2 = "0123456789abcdef"[i];
456 p = open(line, O_RDWR);
457 if (p > 0) {
458 #ifndef __hpux
459 line[5] = 't';
460 #else
461 for (p1 = &line[8]; *p1; p1++)
462 *p1 = *(p1+1);
463 line[9] = 't';
464 #endif
465 chown(line, 0, 0);
466 chmod(line, 0600);
467 #if SunOS == 4
468 if (ioctl(p, TIOCGPGRP, &dummy) == 0
469 || errno != EIO) {
470 chmod(line, 0666);
471 close(p);
472 line[5] = 'p';
473 } else
474 #endif /* SunOS == 4 */
475 return(p);
479 #else /* CRAY */
480 extern lowpty, highpty;
481 struct stat sb;
483 for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {
484 snprintf(myline, sizeof(myline), "/dev/pty/%03d", *ptynum);
485 p = open(myline, 2);
486 if (p < 0)
487 continue;
488 snprintf(line, sizeof(Xline), "/dev/ttyp%03d", *ptynum);
490 * Here are some shenanigans to make sure that there
491 * are no listeners lurking on the line.
493 if(stat(line, &sb) < 0) {
494 close(p);
495 continue;
497 if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
498 chown(line, 0, 0);
499 chmod(line, 0600);
500 close(p);
501 p = open(myline, 2);
502 if (p < 0)
503 continue;
506 * Now it should be safe...check for accessability.
508 if (access(line, 6) == 0)
509 return(p);
510 else {
511 /* no tty side to pty so skip it */
512 close(p);
515 #endif /* CRAY */
516 #endif /* STREAMSPTY */
517 #endif /* OPENPTY */
518 return(-1);
519 #endif
524 tty_isecho(void)
526 return (termbuf.c_lflag & ECHO);
530 tty_flowmode(void)
532 return((termbuf.c_iflag & IXON) ? 1 : 0);
536 tty_restartany(void)
538 return((termbuf.c_iflag & IXANY) ? 1 : 0);
541 void
542 tty_setecho(int on)
544 if (on)
545 termbuf.c_lflag |= ECHO;
546 else
547 termbuf.c_lflag &= ~ECHO;
551 tty_israw(void)
553 return(!(termbuf.c_lflag & ICANON));
556 void
557 tty_binaryin(int on)
559 if (on) {
560 termbuf.c_iflag &= ~ISTRIP;
561 } else {
562 termbuf.c_iflag |= ISTRIP;
566 void
567 tty_binaryout(int on)
569 if (on) {
570 termbuf.c_cflag &= ~(CSIZE|PARENB);
571 termbuf.c_cflag |= CS8;
572 termbuf.c_oflag &= ~OPOST;
573 } else {
574 termbuf.c_cflag &= ~CSIZE;
575 termbuf.c_cflag |= CS7|PARENB;
576 termbuf.c_oflag |= OPOST;
581 tty_isbinaryin(void)
583 return(!(termbuf.c_iflag & ISTRIP));
587 tty_isbinaryout(void)
589 return(!(termbuf.c_oflag&OPOST));
594 tty_issofttab(void)
596 # ifdef OXTABS
597 return (termbuf.c_oflag & OXTABS);
598 # endif
599 # ifdef TABDLY
600 return ((termbuf.c_oflag & TABDLY) == TAB3);
601 # endif
604 void
605 tty_setsofttab(int on)
607 if (on) {
608 # ifdef OXTABS
609 termbuf.c_oflag |= OXTABS;
610 # endif
611 # ifdef TABDLY
612 termbuf.c_oflag &= ~TABDLY;
613 termbuf.c_oflag |= TAB3;
614 # endif
615 } else {
616 # ifdef OXTABS
617 termbuf.c_oflag &= ~OXTABS;
618 # endif
619 # ifdef TABDLY
620 termbuf.c_oflag &= ~TABDLY;
621 termbuf.c_oflag |= TAB0;
622 # endif
627 tty_islitecho(void)
629 # ifdef ECHOCTL
630 return (!(termbuf.c_lflag & ECHOCTL));
631 # endif
632 # ifdef TCTLECH
633 return (!(termbuf.c_lflag & TCTLECH));
634 # endif
635 # if !defined(ECHOCTL) && !defined(TCTLECH)
636 return (0); /* assumes ctl chars are echoed '^x' */
637 # endif
640 void
641 tty_setlitecho(int on)
643 # ifdef ECHOCTL
644 if (on)
645 termbuf.c_lflag &= ~ECHOCTL;
646 else
647 termbuf.c_lflag |= ECHOCTL;
648 # endif
649 # ifdef TCTLECH
650 if (on)
651 termbuf.c_lflag &= ~TCTLECH;
652 else
653 termbuf.c_lflag |= TCTLECH;
654 # endif
658 tty_iscrnl(void)
660 return (termbuf.c_iflag & ICRNL);
664 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
666 #if B4800 != 4800
667 #define DECODE_BAUD
668 #endif
670 #ifdef DECODE_BAUD
673 * A table of available terminal speeds
675 struct termspeeds {
676 int speed;
677 int value;
678 } termspeeds[] = {
679 { 0, B0 }, { 50, B50 }, { 75, B75 },
680 { 110, B110 }, { 134, B134 }, { 150, B150 },
681 { 200, B200 }, { 300, B300 }, { 600, B600 },
682 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
683 { 4800, B4800 },
684 #ifdef B7200
685 { 7200, B7200 },
686 #endif
687 { 9600, B9600 },
688 #ifdef B14400
689 { 14400, B14400 },
690 #endif
691 #ifdef B19200
692 { 19200, B19200 },
693 #endif
694 #ifdef B28800
695 { 28800, B28800 },
696 #endif
697 #ifdef B38400
698 { 38400, B38400 },
699 #endif
700 #ifdef B57600
701 { 57600, B57600 },
702 #endif
703 #ifdef B115200
704 { 115200, B115200 },
705 #endif
706 #ifdef B230400
707 { 230400, B230400 },
708 #endif
709 { -1, 0 }
711 #endif /* DECODE_BUAD */
713 void
714 tty_tspeed(int val)
716 #ifdef DECODE_BAUD
717 struct termspeeds *tp;
719 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
721 if (tp->speed == -1) /* back up to last valid value */
722 --tp;
723 cfsetospeed(&termbuf, tp->value);
724 #else /* DECODE_BUAD */
725 cfsetospeed(&termbuf, val);
726 #endif /* DECODE_BUAD */
729 void
730 tty_rspeed(int val)
732 #ifdef DECODE_BAUD
733 struct termspeeds *tp;
735 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
737 if (tp->speed == -1) /* back up to last valid value */
738 --tp;
739 cfsetispeed(&termbuf, tp->value);
740 #else /* DECODE_BAUD */
741 cfsetispeed(&termbuf, val);
742 #endif /* DECODE_BAUD */
745 #ifdef PARENT_DOES_UTMP
746 extern struct utmp wtmp;
747 extern char wtmpf[];
749 extern void utmp_sig_init (void);
750 extern void utmp_sig_reset (void);
751 extern void utmp_sig_wait (void);
752 extern void utmp_sig_notify (int);
753 # endif /* PARENT_DOES_UTMP */
755 #ifdef STREAMSPTY
757 /* I_FIND seems to live a life of its own */
758 static int my_find(int fd, char *module)
760 #if defined(I_FIND) && defined(I_LIST)
761 static int flag;
762 static struct str_list sl;
763 int n;
764 int i;
766 if(!flag){
767 n = ioctl(fd, I_LIST, 0);
768 if(n < 0){
769 perror("ioctl(fd, I_LIST, 0)");
770 return -1;
772 sl.sl_modlist=(struct str_mlist*)malloc(n * sizeof(struct str_mlist));
773 sl.sl_nmods = n;
774 n = ioctl(fd, I_LIST, &sl);
775 if(n < 0){
776 perror("ioctl(fd, I_LIST, n)");
777 return -1;
779 flag = 1;
782 for(i=0; i<sl.sl_nmods; i++)
783 if(!strcmp(sl.sl_modlist[i].l_name, module))
784 return 1;
785 #endif
786 return 0;
789 static void maybe_push_modules(int fd, char **modules)
791 char **p;
792 int err;
794 for(p=modules; *p; p++){
795 err = my_find(fd, *p);
796 if(err == 1)
797 break;
798 if(err < 0 && errno != EINVAL)
799 fatalperror(net, "my_find()");
800 /* module not pushed or does not exist */
802 /* p points to null or to an already pushed module, now push all
803 modules before this one */
805 for(p--; p >= modules; p--){
806 err = ioctl(fd, I_PUSH, *p);
807 if(err < 0 && errno != EINVAL)
808 fatalperror(net, "I_PUSH");
811 #endif
814 * getptyslave()
816 * Open the slave side of the pty, and do any initialization
817 * that is necessary. The return value is a file descriptor
818 * for the slave side.
820 void getptyslave(void)
822 int t = -1;
824 struct winsize ws;
825 extern int def_row, def_col;
826 extern int def_tspeed, def_rspeed;
828 * Opening the slave side may cause initilization of the
829 * kernel tty structure. We need remember the state of
830 * if linemode was turned on
831 * terminal window size
832 * terminal speed
833 * so that we can re-set them if we need to.
838 * Make sure that we don't have a controlling tty, and
839 * that we are the session (process group) leader.
842 #ifdef HAVE_SETSID
843 if(setsid()<0)
844 fatalperror(net, "setsid()");
845 #else
846 # ifdef TIOCNOTTY
847 t = open(_PATH_TTY, O_RDWR);
848 if (t >= 0) {
849 ioctl(t, TIOCNOTTY, (char *)0);
850 close(t);
852 # endif
853 #endif
855 # ifdef PARENT_DOES_UTMP
857 * Wait for our parent to get the utmp stuff to get done.
859 utmp_sig_wait();
860 # endif
862 t = cleanopen(line);
863 if (t < 0)
864 fatalperror(net, line);
866 #ifdef STREAMSPTY
867 ttyfd = t;
871 * Not all systems have (or need) modules ttcompat and pckt so
872 * don't flag it as a fatal error if they don't exist.
875 if (really_stream)
877 /* these are the streams modules that we want pushed. note
878 that they are in reverse order, ptem will be pushed
879 first. maybe_push_modules() will try to push all modules
880 before the first one that isn't already pushed. i.e if
881 ldterm is pushed, only ttcompat will be attempted.
883 all this is because we don't know which modules are
884 available, and we don't know which modules are already
885 pushed (via autopush, for instance).
889 char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL };
890 char *ptymodules[] = { "pckt", NULL };
892 maybe_push_modules(t, ttymodules);
893 maybe_push_modules(ourpty, ptymodules);
895 #endif
897 * set up the tty modes as we like them to be.
899 init_termbuf();
900 # ifdef TIOCSWINSZ
901 if (def_row || def_col) {
902 memset(&ws, 0, sizeof(ws));
903 ws.ws_col = def_col;
904 ws.ws_row = def_row;
905 ioctl(t, TIOCSWINSZ, (char *)&ws);
907 # endif
910 * Settings for sgtty based systems
914 * Settings for UNICOS (and HPUX)
916 # if defined(_CRAY) || defined(__hpux)
917 termbuf.c_oflag = OPOST|ONLCR|TAB3;
918 termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
919 termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
920 termbuf.c_cflag = EXTB|HUPCL|CS8;
921 # endif
924 * Settings for all other termios/termio based
925 * systems, other than 4.4BSD. In 4.4BSD the
926 * kernel does the initial terminal setup.
928 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43)
929 # ifndef OXTABS
930 # define OXTABS 0
931 # endif
932 termbuf.c_lflag |= ECHO;
933 termbuf.c_oflag |= ONLCR|OXTABS;
934 termbuf.c_iflag |= ICRNL;
935 termbuf.c_iflag &= ~IXOFF;
936 # endif
937 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
938 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
941 * Set the tty modes, and make this our controlling tty.
943 set_termbuf();
944 if (login_tty(t) == -1)
945 fatalperror(net, "login_tty");
946 if (net > 2)
947 close(net);
948 if (ourpty > 2) {
949 close(ourpty);
950 ourpty = -1;
954 #ifndef O_NOCTTY
955 #define O_NOCTTY 0
956 #endif
958 * Open the specified slave side of the pty,
959 * making sure that we have a clean tty.
962 int cleanopen(char *line)
964 int t;
966 #ifdef STREAMSPTY
967 if (!really_stream)
968 #endif
971 * Make sure that other people can't open the
972 * slave side of the connection.
974 chown(line, 0, 0);
975 chmod(line, 0600);
978 #ifdef HAVE_REVOKE
979 revoke(line);
980 #endif
982 t = open(line, O_RDWR|O_NOCTTY);
984 if (t < 0)
985 return(-1);
988 * Hangup anybody else using this ttyp, then reopen it for
989 * ourselves.
991 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
992 signal(SIGHUP, SIG_IGN);
993 #ifdef HAVE_VHANGUP
994 vhangup();
995 #else
996 #endif
997 signal(SIGHUP, SIG_DFL);
998 t = open(line, O_RDWR|O_NOCTTY);
999 if (t < 0)
1000 return(-1);
1001 # endif
1002 # if defined(_CRAY) && defined(TCVHUP)
1004 int i;
1005 signal(SIGHUP, SIG_IGN);
1006 ioctl(t, TCVHUP, (char *)0);
1007 signal(SIGHUP, SIG_DFL);
1009 i = open(line, O_RDWR);
1011 if (i < 0)
1012 return(-1);
1013 close(t);
1014 t = i;
1016 # endif /* defined(CRAY) && defined(TCVHUP) */
1017 return(t);
1020 #if !defined(BSD4_4)
1022 int login_tty(int t)
1024 # if defined(TIOCSCTTY) && !defined(__hpux)
1025 if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
1026 fatalperror(net, "ioctl(sctty)");
1027 # ifdef _CRAY
1029 * Close the hard fd to /dev/ttypXXX, and re-open through
1030 * the indirect /dev/tty interface.
1032 close(t);
1033 if ((t = open("/dev/tty", O_RDWR)) < 0)
1034 fatalperror(net, "open(/dev/tty)");
1035 # endif
1036 # else
1038 * We get our controlling tty assigned as a side-effect
1039 * of opening up a tty device. But on BSD based systems,
1040 * this only happens if our process group is zero. The
1041 * setsid() call above may have set our pgrp, so clear
1042 * it out before opening the tty...
1044 #ifdef HAVE_SETPGID
1045 setpgid(0, 0);
1046 #else
1047 setpgrp(0, 0); /* if setpgid isn't available, setpgrp
1048 probably takes arguments */
1049 #endif
1050 close(open(line, O_RDWR));
1051 # endif
1052 if (t != 0)
1053 dup2(t, 0);
1054 if (t != 1)
1055 dup2(t, 1);
1056 if (t != 2)
1057 dup2(t, 2);
1058 if (t > 2)
1059 close(t);
1060 return(0);
1062 #endif /* BSD <= 43 */
1065 * This comes from ../../bsd/tty.c and should not really be here.
1069 * Clean the tty name. Return a pointer to the cleaned version.
1072 static char *
1073 clean_ttyname (char *tty)
1075 char *res = tty;
1077 if (strncmp (res, _PATH_DEV, strlen(_PATH_DEV)) == 0)
1078 res += strlen(_PATH_DEV);
1079 if (strncmp (res, "pty/", 4) == 0)
1080 res += 4;
1081 if (strncmp (res, "ptym/", 5) == 0)
1082 res += 5;
1083 return res;
1087 * Generate a name usable as an `ut_id', typically without `tty'.
1090 #ifdef HAVE_STRUCT_UTMP_UT_ID
1091 static char *
1092 make_id (char *tty)
1094 char *res = tty;
1096 if (strncmp (res, "pts/", 4) == 0)
1097 res += 4;
1098 if (strncmp (res, "tty", 3) == 0)
1099 res += 3;
1100 return res;
1102 #endif
1105 * startslave(host)
1107 * Given a hostname, do whatever
1108 * is necessary to startup the login process on the slave side of the pty.
1111 /* ARGSUSED */
1112 void
1113 startslave(char *host, int autologin, char *autoname)
1115 int i;
1117 #ifdef AUTHENTICATION
1118 if (!autoname || !autoname[0])
1119 autologin = 0;
1121 if (autologin < auth_level) {
1122 fatal(net, "Authorization failed");
1123 exit(1);
1125 #endif
1128 char *tbuf =
1129 "\r\n*** Connection not encrypted! "
1130 "Communication may be eavesdropped. ***\r\n";
1131 #ifdef ENCRYPTION
1132 if (!no_warn && (encrypt_output == 0 || decrypt_input == 0))
1133 #endif
1134 writenet((unsigned char*)tbuf, strlen(tbuf));
1136 # ifdef PARENT_DOES_UTMP
1137 utmp_sig_init();
1138 # endif /* PARENT_DOES_UTMP */
1140 if ((i = fork()) < 0)
1141 fatalperror(net, "fork");
1142 if (i) {
1143 # ifdef PARENT_DOES_UTMP
1145 * Cray parent will create utmp entry for child and send
1146 * signal to child to tell when done. Child waits for signal
1147 * before doing anything important.
1149 int pid = i;
1150 void sigjob (int);
1152 setpgrp();
1153 utmp_sig_reset(); /* reset handler to default */
1155 * Create utmp entry for child
1157 time(&wtmp.ut_time);
1158 wtmp.ut_type = LOGIN_PROCESS;
1159 wtmp.ut_pid = pid;
1160 strncpy(wtmp.ut_user, "LOGIN", sizeof(wtmp.ut_user));
1161 strncpy(wtmp.ut_host, host, sizeof(wtmp.ut_host));
1162 strncpy(wtmp.ut_line, clean_ttyname(line), sizeof(wtmp.ut_line));
1163 #ifdef HAVE_STRUCT_UTMP_UT_ID
1164 strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id));
1165 #endif
1167 pututline(&wtmp);
1168 endutent();
1169 if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
1170 write(i, &wtmp, sizeof(struct utmp));
1171 close(i);
1173 #ifdef _CRAY
1174 signal(WJSIGNAL, sigjob);
1175 #endif
1176 utmp_sig_notify(pid);
1177 # endif /* PARENT_DOES_UTMP */
1178 } else {
1179 getptyslave();
1180 start_login(host, autologin, autoname);
1181 /*NOTREACHED*/
1185 char *envinit[3];
1186 extern char **environ;
1188 void
1189 init_env(void)
1191 extern char *getenv(const char *);
1192 char **envp;
1194 envp = envinit;
1195 if ((*envp = getenv("TZ")))
1196 *envp++ -= 3;
1197 #if defined(_CRAY) || defined(__hpux)
1198 else
1199 *envp++ = "TZ=GMT0";
1200 #endif
1201 *envp = 0;
1202 environ = envinit;
1206 * scrub_env()
1208 * Remove variables from the environment that might cause login to
1209 * behave in a bad manner. To avoid this, login should be staticly
1210 * linked.
1213 static void scrub_env(void)
1215 static char *remove[] = { "LD_", "_RLD_", "LIBPATH=", "IFS=", NULL };
1217 char **cpp, **cpp2;
1218 char **p;
1220 for (cpp2 = cpp = environ; *cpp; cpp++) {
1221 for(p = remove; *p; p++)
1222 if(strncmp(*cpp, *p, strlen(*p)) == 0)
1223 break;
1224 if(*p == NULL)
1225 *cpp2++ = *cpp;
1227 *cpp2 = 0;
1231 struct arg_val {
1232 int size;
1233 int argc;
1234 char **argv;
1237 static int addarg(struct arg_val*, char*);
1240 * start_login(host)
1242 * Assuming that we are now running as a child processes, this
1243 * function will turn us into the login process.
1246 void
1247 start_login(char *host, int autologin, char *name)
1249 struct arg_val argv;
1250 char *user;
1252 #ifdef HAVE_UTMPX_H
1253 int pid = getpid();
1254 struct utmpx utmpx;
1255 char *clean_tty;
1258 * Create utmp entry for child
1261 clean_tty = clean_ttyname(line);
1262 memset(&utmpx, 0, sizeof(utmpx));
1263 strncpy(utmpx.ut_user, ".telnet", sizeof(utmpx.ut_user));
1264 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1265 #ifdef HAVE_STRUCT_UTMP_UT_ID
1266 strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id));
1267 #endif
1268 utmpx.ut_pid = pid;
1270 utmpx.ut_type = LOGIN_PROCESS;
1272 gettimeofday (&utmpx.ut_tv, NULL);
1273 if (pututxline(&utmpx) == NULL)
1274 fatal(net, "pututxline failed");
1275 #endif
1277 scrub_env();
1280 * -h : pass on name of host.
1281 * WARNING: -h is accepted by login if and only if
1282 * getuid() == 0.
1283 * -p : don't clobber the environment (so terminal type stays set).
1285 * -f : force this login, he has already been authenticated
1288 /* init argv structure */
1289 argv.size=0;
1290 argv.argc=0;
1291 argv.argv=(char**)malloc(0); /*so we can call realloc later */
1292 addarg(&argv, "login");
1293 addarg(&argv, "-h");
1294 addarg(&argv, host);
1295 addarg(&argv, "-p");
1296 if(name[0])
1297 user = name;
1298 else
1299 user = getenv("USER");
1300 #ifdef AUTHENTICATION
1301 if (auth_level < 0 || autologin != AUTH_VALID) {
1302 if(!no_warn)
1303 printf("User not authenticated. "
1304 "Using plaintext username and password\r\n");
1305 if (require_otp) {
1306 addarg(&argv, "-a");
1307 addarg(&argv, "otp");
1309 if(log_unauth)
1310 syslog(LOG_INFO, "unauthenticated access from %s (%s)",
1311 host, user ? user : "unknown user");
1313 if (auth_level >= 0 && autologin == AUTH_VALID)
1314 addarg(&argv, "-f");
1315 #endif
1316 if(user){
1317 addarg(&argv, "--");
1318 addarg(&argv, strdup(user));
1320 if (getenv("USER")) {
1322 * Assume that login will set the USER variable
1323 * correctly. For SysV systems, this means that
1324 * USER will no longer be set, just LOGNAME by
1325 * login. (The problem is that if the auto-login
1326 * fails, and the user then specifies a different
1327 * account name, he can get logged in with both
1328 * LOGNAME and USER in his environment, but the
1329 * USER value will be wrong.
1331 unsetenv("USER");
1333 closelog();
1335 * This sleep(1) is in here so that telnetd can
1336 * finish up with the tty. There's a race condition
1337 * the login banner message gets lost...
1339 sleep(1);
1341 execv(new_login, argv.argv);
1343 syslog(LOG_ERR, "%s: %m\n", new_login);
1344 fatalperror(net, new_login);
1345 /*NOTREACHED*/
1350 static int addarg(struct arg_val *argv, char *val)
1352 if(argv->size <= argv->argc+1){
1353 argv->argv = (char**)realloc(argv->argv, sizeof(char*) * (argv->size + 10));
1354 if(argv->argv == NULL)
1355 return 1; /* this should probably be handled better */
1356 argv->size+=10;
1358 argv->argv[argv->argc++]=val;
1359 argv->argv[argv->argc]=NULL;
1360 return 0;
1365 * rmut()
1367 * This is the function called by cleanup() to
1368 * remove the utmp entry for this person.
1371 #ifdef HAVE_UTMPX_H
1372 static void
1373 rmut(void)
1375 struct utmpx *utxp, utmpx;
1376 char *clean_tty = clean_ttyname(line);
1379 * This updates the utmpx and utmp entries and make a wtmp/x entry
1382 setutxent();
1383 memset(&utmpx, 0, sizeof(utmpx));
1384 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1385 utmpx.ut_type = LOGIN_PROCESS;
1386 utxp = getutxline(&utmpx);
1387 if (utxp) {
1388 utxp->ut_user[0] = '\0';
1389 utxp->ut_type = DEAD_PROCESS;
1390 #ifdef HAVE_STRUCT_UTMPX_UT_EXIT
1391 #ifdef _STRUCT___EXIT_STATUS
1392 utxp->ut_exit.__e_termination = 0;
1393 utxp->ut_exit.__e_exit = 0;
1394 #elif defined(__osf__) /* XXX */
1395 utxp->ut_exit.ut_termination = 0;
1396 utxp->ut_exit.ut_exit = 0;
1397 #else
1398 utxp->ut_exit.e_termination = 0;
1399 utxp->ut_exit.e_exit = 0;
1400 #endif
1401 #endif
1402 gettimeofday(&utxp->ut_tv, NULL);
1403 pututxline(utxp);
1404 #ifdef WTMPX_FILE
1405 updwtmpx(WTMPX_FILE, utxp);
1406 #elif defined(WTMP_FILE)
1407 /* This is a strange system with a utmpx and a wtmp! */
1409 int f = open(wtmpf, O_WRONLY|O_APPEND);
1410 struct utmp wtmp;
1411 if (f >= 0) {
1412 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));
1413 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));
1414 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1415 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));
1416 #endif
1417 time(&wtmp.ut_time);
1418 write(f, &wtmp, sizeof(wtmp));
1419 close(f);
1422 #else
1424 #endif
1426 endutxent();
1427 } /* end of rmut */
1428 #endif
1430 #if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43
1431 static void
1432 rmut(void)
1434 int f;
1435 int found = 0;
1436 struct utmp *u, *utmp;
1437 int nutmp;
1438 struct stat statbf;
1439 char *clean_tty = clean_ttyname(line);
1441 f = open(utmpf, O_RDWR);
1442 if (f >= 0) {
1443 fstat(f, &statbf);
1444 utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
1445 if (!utmp)
1446 syslog(LOG_ERR, "utmp malloc failed");
1447 if (statbf.st_size && utmp) {
1448 nutmp = read(f, utmp, (int)statbf.st_size);
1449 nutmp /= sizeof(struct utmp);
1451 for (u = utmp ; u < &utmp[nutmp] ; u++) {
1452 if (strncmp(u->ut_line,
1453 clean_tty,
1454 sizeof(u->ut_line)) ||
1455 u->ut_name[0]==0)
1456 continue;
1457 lseek(f, ((long)u)-((long)utmp), L_SET);
1458 strncpy(u->ut_name, "", sizeof(u->ut_name));
1459 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1460 strncpy(u->ut_host, "", sizeof(u->ut_host));
1461 #endif
1462 time(&u->ut_time);
1463 write(f, u, sizeof(wtmp));
1464 found++;
1467 close(f);
1469 if (found) {
1470 f = open(wtmpf, O_WRONLY|O_APPEND);
1471 if (f >= 0) {
1472 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));
1473 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));
1474 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1475 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));
1476 #endif
1477 time(&wtmp.ut_time);
1478 write(f, &wtmp, sizeof(wtmp));
1479 close(f);
1482 chmod(line, 0666);
1483 chown(line, 0, 0);
1484 line[strlen("/dev/")] = 'p';
1485 chmod(line, 0666);
1486 chown(line, 0, 0);
1487 } /* end of rmut */
1488 #endif /* CRAY */
1490 #if defined(__hpux) && !defined(HAVE_UTMPX_H)
1491 static void
1492 rmut (char *line)
1494 struct utmp utmp;
1495 struct utmp *utptr;
1496 int fd; /* for /etc/wtmp */
1498 utmp.ut_type = USER_PROCESS;
1499 strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line));
1500 setutent();
1501 utptr = getutline(&utmp);
1502 /* write it out only if it exists */
1503 if (utptr) {
1504 utptr->ut_type = DEAD_PROCESS;
1505 utptr->ut_time = time(NULL);
1506 pututline(utptr);
1507 /* set wtmp entry if wtmp file exists */
1508 if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
1509 write(fd, utptr, sizeof(utmp));
1510 close(fd);
1513 endutent();
1515 chmod(line, 0666);
1516 chown(line, 0, 0);
1517 line[14] = line[13];
1518 line[13] = line[12];
1519 line[8] = 'm';
1520 line[9] = '/';
1521 line[10] = 'p';
1522 line[11] = 't';
1523 line[12] = 'y';
1524 chmod(line, 0666);
1525 chown(line, 0, 0);
1527 #endif
1530 * cleanup()
1532 * This is the routine to call when we are all through, to
1533 * clean up anything that needs to be cleaned up.
1536 #ifdef PARENT_DOES_UTMP
1538 void
1539 cleanup(int sig)
1541 #ifdef _CRAY
1542 static int incleanup = 0;
1543 int t;
1544 int child_status; /* status of child process as returned by waitpid */
1545 int flags = WNOHANG|WUNTRACED;
1548 * 1: Pick up the zombie, if we are being called
1549 * as the signal handler.
1550 * 2: If we are a nested cleanup(), return.
1551 * 3: Try to clean up TMPDIR.
1552 * 4: Fill in utmp with shutdown of process.
1553 * 5: Close down the network and pty connections.
1554 * 6: Finish up the TMPDIR cleanup, if needed.
1556 if (sig == SIGCHLD) {
1557 while (waitpid(-1, &child_status, flags) > 0)
1558 ; /* VOID */
1559 /* Check if the child process was stopped
1560 * rather than exited. We want cleanup only if
1561 * the child has died.
1563 if (WIFSTOPPED(child_status)) {
1564 return;
1567 t = sigblock(sigmask(SIGCHLD));
1568 if (incleanup) {
1569 sigsetmask(t);
1570 return;
1572 incleanup = 1;
1573 sigsetmask(t);
1575 t = cleantmp(&wtmp);
1576 setutent(); /* just to make sure */
1577 #endif /* CRAY */
1578 rmut(line);
1579 close(ourpty);
1580 shutdown(net, 2);
1581 #ifdef _CRAY
1582 if (t == 0)
1583 cleantmp(&wtmp);
1584 #endif /* CRAY */
1585 exit(1);
1588 #else /* PARENT_DOES_UTMP */
1590 void
1591 cleanup(int sig)
1593 #if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)
1594 rmut();
1595 #ifdef HAVE_VHANGUP
1596 #ifndef __sgi
1597 vhangup(); /* XXX */
1598 #endif
1599 #endif
1600 #else
1601 char *p;
1603 p = line + sizeof("/dev/") - 1;
1604 if (logout(p))
1605 logwtmp(p, "", "");
1606 chmod(line, 0666);
1607 chown(line, 0, 0);
1608 *p = 'p';
1609 chmod(line, 0666);
1610 chown(line, 0, 0);
1611 #endif
1612 shutdown(net, 2);
1613 exit(1);
1616 #endif /* PARENT_DOES_UTMP */
1618 #ifdef PARENT_DOES_UTMP
1620 * _utmp_sig_rcv
1621 * utmp_sig_init
1622 * utmp_sig_wait
1623 * These three functions are used to coordinate the handling of
1624 * the utmp file between the server and the soon-to-be-login shell.
1625 * The server actually creates the utmp structure, the child calls
1626 * utmp_sig_wait(), until the server calls utmp_sig_notify() and
1627 * signals the future-login shell to proceed.
1629 static int caught=0; /* NZ when signal intercepted */
1630 static void (*func)(); /* address of previous handler */
1632 void
1633 _utmp_sig_rcv(sig)
1634 int sig;
1636 caught = 1;
1637 signal(SIGUSR1, func);
1640 void
1641 utmp_sig_init()
1644 * register signal handler for UTMP creation
1646 if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1647 fatalperror(net, "telnetd/signal");
1650 void
1651 utmp_sig_reset()
1653 signal(SIGUSR1, func); /* reset handler to default */
1656 # ifdef __hpux
1657 # define sigoff() /* do nothing */
1658 # define sigon() /* do nothing */
1659 # endif
1661 void
1662 utmp_sig_wait()
1665 * Wait for parent to write our utmp entry.
1667 sigoff();
1668 while (caught == 0) {
1669 pause(); /* wait until we get a signal (sigon) */
1670 sigoff(); /* turn off signals while we check caught */
1672 sigon(); /* turn on signals again */
1675 void
1676 utmp_sig_notify(pid)
1678 kill(pid, SIGUSR1);
1681 #ifdef _CRAY
1682 static int gotsigjob = 0;
1684 /*ARGSUSED*/
1685 void
1686 sigjob(sig)
1687 int sig;
1689 int jid;
1690 struct jobtemp *jp;
1692 while ((jid = waitjob(NULL)) != -1) {
1693 if (jid == 0) {
1694 return;
1696 gotsigjob++;
1697 jobend(jid, NULL, NULL);
1702 * jid_getutid:
1703 * called by jobend() before calling cleantmp()
1704 * to find the correct $TMPDIR to cleanup.
1707 struct utmp *
1708 jid_getutid(jid)
1709 int jid;
1711 struct utmp *cur = NULL;
1713 setutent(); /* just to make sure */
1714 while (cur = getutent()) {
1715 if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
1716 return(cur);
1720 return(0);
1724 * Clean up the TMPDIR that login created.
1725 * The first time this is called we pick up the info
1726 * from the utmp. If the job has already gone away,
1727 * then we'll clean up and be done. If not, then
1728 * when this is called the second time it will wait
1729 * for the signal that the job is done.
1732 cleantmp(wtp)
1733 struct utmp *wtp;
1735 struct utmp *utp;
1736 static int first = 1;
1737 int mask, omask, ret;
1738 extern struct utmp *getutid (const struct utmp *_Id);
1741 mask = sigmask(WJSIGNAL);
1743 if (first == 0) {
1744 omask = sigblock(mask);
1745 while (gotsigjob == 0)
1746 sigpause(omask);
1747 return(1);
1749 first = 0;
1750 setutent(); /* just to make sure */
1752 utp = getutid(wtp);
1753 if (utp == 0) {
1754 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1755 return(-1);
1758 * Nothing to clean up if the user shell was never started.
1760 if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
1761 return(1);
1764 * Block the WJSIGNAL while we are in jobend().
1766 omask = sigblock(mask);
1767 ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
1768 sigsetmask(omask);
1769 return(ret);
1773 jobend(jid, path, user)
1774 int jid;
1775 char *path;
1776 char *user;
1778 static int saved_jid = 0;
1779 static int pty_saved_jid = 0;
1780 static char saved_path[sizeof(wtmp.ut_tpath)+1];
1781 static char saved_user[sizeof(wtmp.ut_user)+1];
1784 * this little piece of code comes into play
1785 * only when ptyreconnect is used to reconnect
1786 * to an previous session.
1788 * this is the only time when the
1789 * "saved_jid != jid" code is executed.
1792 if ( saved_jid && saved_jid != jid ) {
1793 if (!path) { /* called from signal handler */
1794 pty_saved_jid = jid;
1795 } else {
1796 pty_saved_jid = saved_jid;
1800 if (path) {
1801 strncpy(saved_path, path, sizeof(wtmp.ut_tpath));
1802 strncpy(saved_user, user, sizeof(wtmp.ut_user));
1803 saved_path[sizeof(saved_path)] = '\0';
1804 saved_user[sizeof(saved_user)] = '\0';
1806 if (saved_jid == 0) {
1807 saved_jid = jid;
1808 return(0);
1811 /* if the jid has changed, get the correct entry from the utmp file */
1813 if ( saved_jid != jid ) {
1814 struct utmp *utp = NULL;
1815 struct utmp *jid_getutid();
1817 utp = jid_getutid(pty_saved_jid);
1819 if (utp == 0) {
1820 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1821 return(-1);
1824 cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
1825 return(1);
1828 cleantmpdir(jid, saved_path, saved_user);
1829 return(1);
1833 * Fork a child process to clean up the TMPDIR
1835 cleantmpdir(jid, tpath, user)
1836 int jid;
1837 char *tpath;
1838 char *user;
1840 switch(fork()) {
1841 case -1:
1842 syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
1843 tpath);
1844 break;
1845 case 0:
1846 execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0);
1847 syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1848 tpath, CLEANTMPCMD);
1849 exit(1);
1850 default:
1852 * Forget about child. We will exit, and
1853 * /etc/init will pick it up.
1855 break;
1858 #endif /* CRAY */
1859 #endif /* defined(PARENT_DOES_UTMP) */