No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / appl / telnet / telnetd / sys_term.c
blob1878451242207c3b720f9b7ecf119d7a692c61cb
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("$Heimdal: sys_term.c 22390 2007-12-31 10:12:48Z lha $"
37 "$NetBSD$");
39 #if defined(_CRAY) || (defined(__hpux) && !defined(HAVE_UTMPX_H))
40 # define PARENT_DOES_UTMP
41 #endif
43 #ifdef HAVE_UTMP_H
44 #include <utmp.h>
45 #endif
47 #ifdef HAVE_UTMPX_H
48 #include <utmpx.h>
49 #endif
51 #ifdef HAVE_UTMPX_H
52 struct utmpx wtmp;
53 #elif defined(HAVE_UTMP_H)
54 struct utmp wtmp;
55 #endif /* HAVE_UTMPX_H */
57 #ifdef HAVE_STRUCT_UTMP_UT_HOST
58 int utmp_len = sizeof(wtmp.ut_host);
59 #else
60 int utmp_len = MaxHostNameLen;
61 #endif
63 #ifndef UTMP_FILE
64 #ifdef _PATH_UTMP
65 #define UTMP_FILE _PATH_UTMP
66 #else
67 #define UTMP_FILE "/etc/utmp"
68 #endif
69 #endif
71 #if !defined(WTMP_FILE) && defined(_PATH_WTMP)
72 #define WTMP_FILE _PATH_WTMP
73 #endif
75 #ifndef PARENT_DOES_UTMP
76 #ifdef WTMP_FILE
77 char wtmpf[] = WTMP_FILE;
78 #else
79 char wtmpf[] = "/usr/adm/wtmp";
80 #endif
81 char utmpf[] = UTMP_FILE;
82 #else /* PARENT_DOES_UTMP */
83 #ifdef WTMP_FILE
84 char wtmpf[] = WTMP_FILE;
85 #else
86 char wtmpf[] = "/etc/wtmp";
87 #endif
88 #endif /* PARENT_DOES_UTMP */
90 #ifdef HAVE_TMPDIR_H
91 #include <tmpdir.h>
92 #endif /* CRAY */
94 #if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY)
95 #include <sys/tty.h>
96 #endif
97 #ifdef t_erase
98 #undef t_erase
99 #undef t_kill
100 #undef t_intrc
101 #undef t_quitc
102 #undef t_startc
103 #undef t_stopc
104 #undef t_eofc
105 #undef t_brkc
106 #undef t_suspc
107 #undef t_dsuspc
108 #undef t_rprntc
109 #undef t_flushc
110 #undef t_werasc
111 #undef t_lnextc
112 #endif
114 #ifdef HAVE_TERMIOS_H
115 #include <termios.h>
116 #else
117 #ifdef HAVE_TERMIO_H
118 #include <termio.h>
119 #endif
120 #endif
122 #ifdef HAVE_UTIL_H
123 #include <util.h>
124 #endif
125 #ifdef HAVE_LIBUTIL_H
126 #include <libutil.h>
127 #endif
129 # ifndef TCSANOW
130 # ifdef TCSETS
131 # define TCSANOW TCSETS
132 # define TCSADRAIN TCSETSW
133 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
134 # else
135 # ifdef TCSETA
136 # define TCSANOW TCSETA
137 # define TCSADRAIN TCSETAW
138 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
139 # else
140 # define TCSANOW TIOCSETA
141 # define TCSADRAIN TIOCSETAW
142 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
143 # endif
144 # endif
145 # define tcsetattr(f, a, t) ioctl(f, a, t)
146 # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
147 (tp)->c_cflag |= (val)
148 # define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
149 # ifdef CIBAUD
150 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
151 (tp)->c_cflag |= ((val)<<IBSHIFT)
152 # define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
153 # else
154 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
155 (tp)->c_cflag |= (val)
156 # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
157 # endif
158 # endif /* TCSANOW */
159 struct termios termbuf, termbuf2; /* pty control structure */
160 # ifdef STREAMSPTY
161 static int ttyfd = -1;
162 int really_stream = 0;
163 # endif
165 const char *new_login = _PATH_LOGIN;
168 * init_termbuf()
169 * copy_termbuf(cp)
170 * set_termbuf()
172 * These three routines are used to get and set the "termbuf" structure
173 * to and from the kernel. init_termbuf() gets the current settings.
174 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
175 * set_termbuf() writes the structure into the kernel.
178 void
179 init_termbuf(void)
181 # ifdef STREAMSPTY
182 if (really_stream)
183 tcgetattr(ttyfd, &termbuf);
184 else
185 # endif
186 tcgetattr(ourpty, &termbuf);
187 termbuf2 = termbuf;
190 void
191 set_termbuf(void)
194 * Only make the necessary changes.
196 if (memcmp(&termbuf, &termbuf2, sizeof(termbuf))) {
197 # ifdef STREAMSPTY
198 if (really_stream)
199 tcsetattr(ttyfd, TCSANOW, &termbuf);
200 else
201 # endif
202 tcsetattr(ourpty, TCSANOW, &termbuf);
208 * spcset(func, valp, valpp)
210 * This function takes various special characters (func), and
211 * sets *valp to the current value of that character, and
212 * *valpp to point to where in the "termbuf" structure that
213 * value is kept.
215 * It returns the SLC_ level of support for this function.
220 spcset(int func, cc_t *valp, cc_t **valpp)
223 #define setval(a, b) *valp = termbuf.c_cc[a]; \
224 *valpp = &termbuf.c_cc[a]; \
225 return(b);
226 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
228 switch(func) {
229 case SLC_EOF:
230 setval(VEOF, SLC_VARIABLE);
231 case SLC_EC:
232 setval(VERASE, SLC_VARIABLE);
233 case SLC_EL:
234 setval(VKILL, SLC_VARIABLE);
235 case SLC_IP:
236 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
237 case SLC_ABORT:
238 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
239 case SLC_XON:
240 #ifdef VSTART
241 setval(VSTART, SLC_VARIABLE);
242 #else
243 defval(0x13);
244 #endif
245 case SLC_XOFF:
246 #ifdef VSTOP
247 setval(VSTOP, SLC_VARIABLE);
248 #else
249 defval(0x11);
250 #endif
251 case SLC_EW:
252 #ifdef VWERASE
253 setval(VWERASE, SLC_VARIABLE);
254 #else
255 defval(0);
256 #endif
257 case SLC_RP:
258 #ifdef VREPRINT
259 setval(VREPRINT, SLC_VARIABLE);
260 #else
261 defval(0);
262 #endif
263 case SLC_LNEXT:
264 #ifdef VLNEXT
265 setval(VLNEXT, SLC_VARIABLE);
266 #else
267 defval(0);
268 #endif
269 case SLC_AO:
270 #if !defined(VDISCARD) && defined(VFLUSHO)
271 # define VDISCARD VFLUSHO
272 #endif
273 #ifdef VDISCARD
274 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
275 #else
276 defval(0);
277 #endif
278 case SLC_SUSP:
279 #ifdef VSUSP
280 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
281 #else
282 defval(0);
283 #endif
284 #ifdef VEOL
285 case SLC_FORW1:
286 setval(VEOL, SLC_VARIABLE);
287 #endif
288 #ifdef VEOL2
289 case SLC_FORW2:
290 setval(VEOL2, SLC_VARIABLE);
291 #endif
292 case SLC_AYT:
293 #ifdef VSTATUS
294 setval(VSTATUS, SLC_VARIABLE);
295 #else
296 defval(0);
297 #endif
299 case SLC_BRK:
300 case SLC_SYNCH:
301 case SLC_EOR:
302 defval(0);
304 default:
305 *valp = 0;
306 *valpp = 0;
307 return(SLC_NOSUPPORT);
311 #ifdef _CRAY
313 * getnpty()
315 * Return the number of pty's configured into the system.
318 getnpty()
320 #ifdef _SC_CRAY_NPTY
321 int numptys;
323 if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
324 return numptys;
325 else
326 #endif /* _SC_CRAY_NPTY */
327 return 128;
329 #endif /* CRAY */
332 * getpty()
334 * Allocate a pty. As a side effect, the external character
335 * array "line" contains the name of the slave side.
337 * Returns the file descriptor of the opened pty.
340 static int ptyslavefd = -1;
342 static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
343 char *line = Xline;
345 #ifdef _CRAY
346 char myline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
347 #endif /* CRAY */
349 #if !defined(HAVE_PTSNAME) && defined(STREAMSPTY)
350 static char *ptsname(int fd)
352 #ifdef HAVE_TTYNAME
353 return ttyname(fd);
354 #else
355 return NULL;
356 #endif
358 #endif
360 int getpty(int *ptynum)
362 #if defined(HAVE_OPENPTY) || defined(__linux) || defined(__osf__) /* XXX */
364 int master;
365 int slave;
366 if(openpty(&master, &slave, line, 0, 0) == 0){
367 ptyslavefd = slave;
368 return master;
371 #endif /* HAVE_OPENPTY .... */
372 #ifdef HAVE__GETPTY
374 int master;
375 char *p;
376 p = _getpty(&master, O_RDWR, 0600, 1);
377 if(p == NULL)
378 return -1;
379 strlcpy(line, p, sizeof(Xline));
380 return master;
382 #endif
384 #ifdef STREAMSPTY
386 char *clone[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm",
387 "/dev/ptym/clone", 0 };
389 char **q;
390 int p;
391 for(q=clone; *q; q++){
392 p=open(*q, O_RDWR);
393 if(p >= 0){
394 #ifdef HAVE_GRANTPT
395 grantpt(p);
396 #endif
397 #ifdef HAVE_UNLOCKPT
398 unlockpt(p);
399 #endif
400 strlcpy(line, ptsname(p), sizeof(Xline));
401 really_stream = 1;
402 return p;
406 #endif /* STREAMSPTY */
407 #ifndef _CRAY
409 int p;
410 char *cp, *p1, *p2;
411 int i;
413 #ifndef __hpux
414 snprintf(line, sizeof(Xline), "/dev/ptyXX");
415 p1 = &line[8];
416 p2 = &line[9];
417 #else
418 snprintf(line, sizeof(Xline), "/dev/ptym/ptyXX");
419 p1 = &line[13];
420 p2 = &line[14];
421 #endif
424 for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
425 struct stat stb;
427 *p1 = *cp;
428 *p2 = '0';
430 * This stat() check is just to keep us from
431 * looping through all 256 combinations if there
432 * aren't that many ptys available.
434 if (stat(line, &stb) < 0)
435 break;
436 for (i = 0; i < 16; i++) {
437 *p2 = "0123456789abcdef"[i];
438 p = open(line, O_RDWR);
439 if (p > 0) {
440 #if SunOS == 40
441 int dummy;
442 #endif
444 #ifndef __hpux
445 line[5] = 't';
446 #else
447 for (p1 = &line[8]; *p1; p1++)
448 *p1 = *(p1+1);
449 line[9] = 't';
450 #endif
451 chown(line, 0, 0);
452 chmod(line, 0600);
453 #if SunOS == 40
454 if (ioctl(p, TIOCGPGRP, &dummy) == 0
455 || errno != EIO) {
456 chmod(line, 0666);
457 close(p);
458 line[5] = 'p';
459 } else
460 #endif /* SunOS == 40 */
461 return(p);
466 #else /* CRAY */
468 extern lowpty, highpty;
469 struct stat sb;
470 int p;
472 for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {
473 snprintf(myline, sizeof(myline), "/dev/pty/%03d", *ptynum);
474 p = open(myline, 2);
475 if (p < 0)
476 continue;
477 snprintf(line, sizeof(Xline), "/dev/ttyp%03d", *ptynum);
479 * Here are some shenanigans to make sure that there
480 * are no listeners lurking on the line.
482 if(stat(line, &sb) < 0) {
483 close(p);
484 continue;
486 if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
487 chown(line, 0, 0);
488 chmod(line, 0600);
489 close(p);
490 p = open(myline, 2);
491 if (p < 0)
492 continue;
495 * Now it should be safe...check for accessability.
497 if (access(line, 6) == 0)
498 return(p);
499 else {
500 /* no tty side to pty so skip it */
501 close(p);
505 #endif /* CRAY */
506 return(-1);
511 tty_isecho(void)
513 return (termbuf.c_lflag & ECHO);
517 tty_flowmode(void)
519 return((termbuf.c_iflag & IXON) ? 1 : 0);
523 tty_restartany(void)
525 return((termbuf.c_iflag & IXANY) ? 1 : 0);
528 void
529 tty_setecho(int on)
531 if (on)
532 termbuf.c_lflag |= ECHO;
533 else
534 termbuf.c_lflag &= ~ECHO;
538 tty_israw(void)
540 return(!(termbuf.c_lflag & ICANON));
543 void
544 tty_binaryin(int on)
546 if (on) {
547 termbuf.c_iflag &= ~ISTRIP;
548 } else {
549 termbuf.c_iflag |= ISTRIP;
553 void
554 tty_binaryout(int on)
556 if (on) {
557 termbuf.c_cflag &= ~(CSIZE|PARENB);
558 termbuf.c_cflag |= CS8;
559 termbuf.c_oflag &= ~OPOST;
560 } else {
561 termbuf.c_cflag &= ~CSIZE;
562 termbuf.c_cflag |= CS7|PARENB;
563 termbuf.c_oflag |= OPOST;
568 tty_isbinaryin(void)
570 return(!(termbuf.c_iflag & ISTRIP));
574 tty_isbinaryout(void)
576 return(!(termbuf.c_oflag&OPOST));
581 tty_issofttab(void)
583 # ifdef OXTABS
584 return (termbuf.c_oflag & OXTABS);
585 # endif
586 # ifdef TABDLY
587 return ((termbuf.c_oflag & TABDLY) == TAB3);
588 # endif
591 void
592 tty_setsofttab(int on)
594 if (on) {
595 # ifdef OXTABS
596 termbuf.c_oflag |= OXTABS;
597 # endif
598 # ifdef TABDLY
599 termbuf.c_oflag &= ~TABDLY;
600 termbuf.c_oflag |= TAB3;
601 # endif
602 } else {
603 # ifdef OXTABS
604 termbuf.c_oflag &= ~OXTABS;
605 # endif
606 # ifdef TABDLY
607 termbuf.c_oflag &= ~TABDLY;
608 termbuf.c_oflag |= TAB0;
609 # endif
614 tty_islitecho(void)
616 # ifdef ECHOCTL
617 return (!(termbuf.c_lflag & ECHOCTL));
618 # endif
619 # ifdef TCTLECH
620 return (!(termbuf.c_lflag & TCTLECH));
621 # endif
622 # if !defined(ECHOCTL) && !defined(TCTLECH)
623 return (0); /* assumes ctl chars are echoed '^x' */
624 # endif
627 void
628 tty_setlitecho(int on)
630 # ifdef ECHOCTL
631 if (on)
632 termbuf.c_lflag &= ~ECHOCTL;
633 else
634 termbuf.c_lflag |= ECHOCTL;
635 # endif
636 # ifdef TCTLECH
637 if (on)
638 termbuf.c_lflag &= ~TCTLECH;
639 else
640 termbuf.c_lflag |= TCTLECH;
641 # endif
645 tty_iscrnl(void)
647 return (termbuf.c_iflag & ICRNL);
651 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
653 #if B4800 != 4800
654 #define DECODE_BAUD
655 #endif
657 #ifdef DECODE_BAUD
660 * A table of available terminal speeds
662 struct termspeeds {
663 int speed;
664 int value;
665 } termspeeds[] = {
666 { 0, B0 }, { 50, B50 }, { 75, B75 },
667 { 110, B110 }, { 134, B134 }, { 150, B150 },
668 { 200, B200 }, { 300, B300 }, { 600, B600 },
669 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
670 { 4800, B4800 },
671 #ifdef B7200
672 { 7200, B7200 },
673 #endif
674 { 9600, B9600 },
675 #ifdef B14400
676 { 14400, B14400 },
677 #endif
678 #ifdef B19200
679 { 19200, B19200 },
680 #endif
681 #ifdef B28800
682 { 28800, B28800 },
683 #endif
684 #ifdef B38400
685 { 38400, B38400 },
686 #endif
687 #ifdef B57600
688 { 57600, B57600 },
689 #endif
690 #ifdef B115200
691 { 115200, B115200 },
692 #endif
693 #ifdef B230400
694 { 230400, B230400 },
695 #endif
696 { -1, 0 }
698 #endif /* DECODE_BUAD */
700 void
701 tty_tspeed(int val)
703 #ifdef DECODE_BAUD
704 struct termspeeds *tp;
706 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
708 if (tp->speed == -1) /* back up to last valid value */
709 --tp;
710 cfsetospeed(&termbuf, tp->value);
711 #else /* DECODE_BUAD */
712 cfsetospeed(&termbuf, val);
713 #endif /* DECODE_BUAD */
716 void
717 tty_rspeed(int val)
719 #ifdef DECODE_BAUD
720 struct termspeeds *tp;
722 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
724 if (tp->speed == -1) /* back up to last valid value */
725 --tp;
726 cfsetispeed(&termbuf, tp->value);
727 #else /* DECODE_BAUD */
728 cfsetispeed(&termbuf, val);
729 #endif /* DECODE_BAUD */
732 #ifdef PARENT_DOES_UTMP
733 extern struct utmp wtmp;
734 extern char wtmpf[];
736 extern void utmp_sig_init (void);
737 extern void utmp_sig_reset (void);
738 extern void utmp_sig_wait (void);
739 extern void utmp_sig_notify (int);
740 # endif /* PARENT_DOES_UTMP */
742 #ifdef STREAMSPTY
744 /* I_FIND seems to live a life of its own */
745 static int my_find(int fd, char *module)
747 #if defined(I_FIND) && defined(I_LIST)
748 static int flag;
749 static struct str_list sl;
750 int n;
751 int i;
753 if(!flag){
754 n = ioctl(fd, I_LIST, 0);
755 if(n < 0){
756 perror("ioctl(fd, I_LIST, 0)");
757 return -1;
759 sl.sl_modlist=(struct str_mlist*)malloc(n * sizeof(struct str_mlist));
760 sl.sl_nmods = n;
761 n = ioctl(fd, I_LIST, &sl);
762 if(n < 0){
763 perror("ioctl(fd, I_LIST, n)");
764 return -1;
766 flag = 1;
769 for(i=0; i<sl.sl_nmods; i++)
770 if(!strcmp(sl.sl_modlist[i].l_name, module))
771 return 1;
772 #endif
773 return 0;
776 static void maybe_push_modules(int fd, char **modules)
778 char **p;
779 int err;
781 for(p=modules; *p; p++){
782 err = my_find(fd, *p);
783 if(err == 1)
784 break;
785 if(err < 0 && errno != EINVAL)
786 fatalperror(net, "my_find()");
787 /* module not pushed or does not exist */
789 /* p points to null or to an already pushed module, now push all
790 modules before this one */
792 for(p--; p >= modules; p--){
793 err = ioctl(fd, I_PUSH, *p);
794 if(err < 0 && errno != EINVAL)
795 fatalperror(net, "I_PUSH");
798 #endif
801 * getptyslave()
803 * Open the slave side of the pty, and do any initialization
804 * that is necessary. The return value is a file descriptor
805 * for the slave side.
807 void getptyslave(void)
809 int t = -1;
811 struct winsize ws;
813 * Opening the slave side may cause initilization of the
814 * kernel tty structure. We need remember the state of
815 * if linemode was turned on
816 * terminal window size
817 * terminal speed
818 * so that we can re-set them if we need to.
823 * Make sure that we don't have a controlling tty, and
824 * that we are the session (process group) leader.
827 #ifdef HAVE_SETSID
828 if(setsid()<0)
829 fatalperror(net, "setsid()");
830 #else
831 # ifdef TIOCNOTTY
832 t = open(_PATH_TTY, O_RDWR);
833 if (t >= 0) {
834 ioctl(t, TIOCNOTTY, (char *)0);
835 close(t);
837 # endif
838 #endif
840 # ifdef PARENT_DOES_UTMP
842 * Wait for our parent to get the utmp stuff to get done.
844 utmp_sig_wait();
845 # endif
847 t = cleanopen(line);
848 if (t < 0)
849 fatalperror(net, line);
851 #ifdef STREAMSPTY
852 ttyfd = t;
856 * Not all systems have (or need) modules ttcompat and pckt so
857 * don't flag it as a fatal error if they don't exist.
860 if (really_stream)
862 /* these are the streams modules that we want pushed. note
863 that they are in reverse order, ptem will be pushed
864 first. maybe_push_modules() will try to push all modules
865 before the first one that isn't already pushed. i.e if
866 ldterm is pushed, only ttcompat will be attempted.
868 all this is because we don't know which modules are
869 available, and we don't know which modules are already
870 pushed (via autopush, for instance).
874 char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL };
875 char *ptymodules[] = { "pckt", NULL };
877 maybe_push_modules(t, ttymodules);
878 maybe_push_modules(ourpty, ptymodules);
880 #endif
882 * set up the tty modes as we like them to be.
884 init_termbuf();
885 # ifdef TIOCSWINSZ
886 if (def_row || def_col) {
887 memset(&ws, 0, sizeof(ws));
888 ws.ws_col = def_col;
889 ws.ws_row = def_row;
890 ioctl(t, TIOCSWINSZ, (char *)&ws);
892 # endif
895 * Settings for sgtty based systems
899 * Settings for UNICOS (and HPUX)
901 # if defined(_CRAY) || defined(__hpux)
902 termbuf.c_oflag = OPOST|ONLCR|TAB3;
903 termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
904 termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
905 termbuf.c_cflag = EXTB|HUPCL|CS8;
906 # endif
909 * Settings for all other termios/termio based
910 * systems, other than 4.4BSD. In 4.4BSD the
911 * kernel does the initial terminal setup.
913 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43)
914 # ifndef OXTABS
915 # define OXTABS 0
916 # endif
917 termbuf.c_lflag |= ECHO;
918 termbuf.c_oflag |= ONLCR|OXTABS;
919 termbuf.c_iflag |= ICRNL;
920 termbuf.c_iflag &= ~IXOFF;
921 # endif
922 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
923 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
926 * Set the tty modes, and make this our controlling tty.
928 set_termbuf();
929 if (login_tty(t) == -1)
930 fatalperror(net, "login_tty");
931 if (net > 2)
932 close(net);
933 if (ourpty > 2) {
934 close(ourpty);
935 ourpty = -1;
939 #ifndef O_NOCTTY
940 #define O_NOCTTY 0
941 #endif
943 * Open the specified slave side of the pty,
944 * making sure that we have a clean tty.
947 int cleanopen(char *line)
949 int t;
951 if (ptyslavefd != -1)
952 return ptyslavefd;
954 #ifdef STREAMSPTY
955 if (!really_stream)
956 #endif
959 * Make sure that other people can't open the
960 * slave side of the connection.
962 chown(line, 0, 0);
963 chmod(line, 0600);
966 #ifdef HAVE_REVOKE
967 revoke(line);
968 #endif
970 t = open(line, O_RDWR|O_NOCTTY);
972 if (t < 0)
973 return(-1);
976 * Hangup anybody else using this ttyp, then reopen it for
977 * ourselves.
979 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
980 signal(SIGHUP, SIG_IGN);
981 #ifdef HAVE_VHANGUP
982 vhangup();
983 #else
984 #endif
985 signal(SIGHUP, SIG_DFL);
986 t = open(line, O_RDWR|O_NOCTTY);
987 if (t < 0)
988 return(-1);
989 # endif
990 # if defined(_CRAY) && defined(TCVHUP)
992 int i;
993 signal(SIGHUP, SIG_IGN);
994 ioctl(t, TCVHUP, (char *)0);
995 signal(SIGHUP, SIG_DFL);
997 i = open(line, O_RDWR);
999 if (i < 0)
1000 return(-1);
1001 close(t);
1002 t = i;
1004 # endif /* defined(CRAY) && defined(TCVHUP) */
1005 return(t);
1008 #if !defined(BSD4_4)
1010 int login_tty(int t)
1012 # if defined(TIOCSCTTY) && !defined(__hpux)
1013 if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
1014 fatalperror(net, "ioctl(sctty)");
1015 # ifdef _CRAY
1017 * Close the hard fd to /dev/ttypXXX, and re-open through
1018 * the indirect /dev/tty interface.
1020 close(t);
1021 if ((t = open("/dev/tty", O_RDWR)) < 0)
1022 fatalperror(net, "open(/dev/tty)");
1023 # endif
1024 # else
1026 * We get our controlling tty assigned as a side-effect
1027 * of opening up a tty device. But on BSD based systems,
1028 * this only happens if our process group is zero. The
1029 * setsid() call above may have set our pgrp, so clear
1030 * it out before opening the tty...
1032 #ifdef HAVE_SETPGID
1033 setpgid(0, 0);
1034 #else
1035 setpgrp(0, 0); /* if setpgid isn't available, setpgrp
1036 probably takes arguments */
1037 #endif
1038 close(open(line, O_RDWR));
1039 # endif
1040 if (t != 0)
1041 dup2(t, 0);
1042 if (t != 1)
1043 dup2(t, 1);
1044 if (t != 2)
1045 dup2(t, 2);
1046 if (t > 2)
1047 close(t);
1048 return(0);
1050 #endif /* BSD <= 43 */
1053 * This comes from ../../bsd/tty.c and should not really be here.
1057 * Clean the tty name. Return a pointer to the cleaned version.
1060 static char * clean_ttyname (char *) __attribute__((unused));
1062 static char *
1063 clean_ttyname (char *tty)
1065 char *res = tty;
1067 if (strncmp (res, _PATH_DEV, strlen(_PATH_DEV)) == 0)
1068 res += strlen(_PATH_DEV);
1069 if (strncmp (res, "pty/", 4) == 0)
1070 res += 4;
1071 if (strncmp (res, "ptym/", 5) == 0)
1072 res += 5;
1073 return res;
1077 * Generate a name usable as an `ut_id', typically without `tty'.
1080 #ifdef HAVE_STRUCT_UTMP_UT_ID
1081 static char *
1082 make_id (char *tty)
1084 char *res = tty;
1086 if (strncmp (res, "pts/", 4) == 0)
1087 res += 4;
1088 if (strncmp (res, "tty", 3) == 0)
1089 res += 3;
1090 return res;
1092 #endif
1095 * startslave(host)
1097 * Given a hostname, do whatever
1098 * is necessary to startup the login process on the slave side of the pty.
1101 /* ARGSUSED */
1102 void
1103 startslave(const char *host, const char *utmp_host,
1104 int autologin, char *autoname)
1106 int i;
1108 #ifdef AUTHENTICATION
1109 if (!autoname || !autoname[0])
1110 autologin = 0;
1112 if (autologin < auth_level) {
1113 fatal(net, "Authorization failed");
1114 exit(1);
1116 #endif
1119 char *tbuf =
1120 "\r\n*** Connection not encrypted! "
1121 "Communication may be eavesdropped. ***\r\n";
1122 #ifdef ENCRYPTION
1123 if (!no_warn && (encrypt_output == 0 || decrypt_input == 0))
1124 #endif
1125 writenet(tbuf, strlen(tbuf));
1127 # ifdef PARENT_DOES_UTMP
1128 utmp_sig_init();
1129 # endif /* PARENT_DOES_UTMP */
1131 if ((i = fork()) < 0)
1132 fatalperror(net, "fork");
1133 if (i) {
1134 # ifdef PARENT_DOES_UTMP
1136 * Cray parent will create utmp entry for child and send
1137 * signal to child to tell when done. Child waits for signal
1138 * before doing anything important.
1140 int pid = i;
1141 void sigjob (int);
1143 setpgrp();
1144 utmp_sig_reset(); /* reset handler to default */
1146 * Create utmp entry for child
1148 wtmp.ut_time = time(NULL);
1149 wtmp.ut_type = LOGIN_PROCESS;
1150 wtmp.ut_pid = pid;
1151 strncpy(wtmp.ut_user, "LOGIN", sizeof(wtmp.ut_user));
1152 strncpy(wtmp.ut_host, utmp_host, sizeof(wtmp.ut_host));
1153 strncpy(wtmp.ut_line, clean_ttyname(line), sizeof(wtmp.ut_line));
1154 #ifdef HAVE_STRUCT_UTMP_UT_ID
1155 strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id));
1156 #endif
1158 pututline(&wtmp);
1159 endutent();
1160 if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
1161 write(i, &wtmp, sizeof(struct utmp));
1162 close(i);
1164 #ifdef _CRAY
1165 signal(WJSIGNAL, sigjob);
1166 #endif
1167 utmp_sig_notify(pid);
1168 # endif /* PARENT_DOES_UTMP */
1169 } else {
1170 getptyslave();
1171 #if defined(DCE)
1172 /* if we authenticated via K5, try and join the PAG */
1173 kerberos5_dfspag();
1174 #endif
1175 start_login(host, autologin, autoname);
1176 /*NOTREACHED*/
1180 char *envinit[3];
1181 extern char **environ;
1183 void
1184 init_env(void)
1186 char **envp;
1188 envp = envinit;
1189 if ((*envp = getenv("TZ")))
1190 *envp++ -= 3;
1191 #if defined(_CRAY) || defined(__hpux)
1192 else
1193 *envp++ = "TZ=GMT0";
1194 #endif
1195 *envp = 0;
1196 environ = envinit;
1200 * scrub_env()
1202 * We only accept the environment variables listed below.
1205 static void
1206 scrub_env(void)
1208 static const char *reject[] = {
1209 "TERMCAP=/",
1210 NULL
1213 static const char *accept[] = {
1214 "XAUTH=", "XAUTHORITY=", "DISPLAY=",
1215 "TERM=",
1216 "EDITOR=",
1217 "PAGER=",
1218 "PRINTER=",
1219 "LOGNAME=",
1220 "POSIXLY_CORRECT=",
1221 "TERMCAP=",
1222 NULL
1225 char **cpp, **cpp2;
1226 const char **p;
1228 for (cpp2 = cpp = environ; *cpp; cpp++) {
1229 int reject_it = 0;
1231 for(p = reject; *p; p++)
1232 if(strncmp(*cpp, *p, strlen(*p)) == 0) {
1233 reject_it = 1;
1234 break;
1236 if (reject_it)
1237 continue;
1239 for(p = accept; *p; p++)
1240 if(strncmp(*cpp, *p, strlen(*p)) == 0)
1241 break;
1242 if(*p != NULL)
1243 *cpp2++ = *cpp;
1245 *cpp2 = NULL;
1249 struct arg_val {
1250 int size;
1251 int argc;
1252 char **argv;
1255 static void addarg(struct arg_val*, const char*);
1258 * start_login(host)
1260 * Assuming that we are now running as a child processes, this
1261 * function will turn us into the login process.
1264 void
1265 start_login(const char *host, int autologin, char *name)
1267 struct arg_val argv;
1268 char *user;
1269 int save_errno;
1271 #ifdef ENCRYPTION
1272 encrypt_output = NULL;
1273 decrypt_input = NULL;
1274 #endif
1276 #ifdef HAVE_UTMPX_H
1278 int pid = getpid();
1279 struct utmpx utmpx;
1280 struct timeval tv;
1281 char *clean_tty;
1284 * Create utmp entry for child
1287 clean_tty = clean_ttyname(line);
1288 memset(&utmpx, 0, sizeof(utmpx));
1289 strncpy(utmpx.ut_user, ".telnet", sizeof(utmpx.ut_user));
1290 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1291 #ifdef HAVE_STRUCT_UTMP_UT_ID
1292 strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id));
1293 #endif
1294 utmpx.ut_pid = pid;
1296 utmpx.ut_type = LOGIN_PROCESS;
1298 gettimeofday (&tv, NULL);
1299 utmpx.ut_tv.tv_sec = tv.tv_sec;
1300 utmpx.ut_tv.tv_usec = tv.tv_usec;
1302 if (pututxline(&utmpx) == NULL)
1303 fatal(net, "pututxline failed");
1305 #endif
1307 scrub_env();
1310 * -h : pass on name of host.
1311 * WARNING: -h is accepted by login if and only if
1312 * getuid() == 0.
1313 * -p : don't clobber the environment (so terminal type stays set).
1315 * -f : force this login, he has already been authenticated
1318 /* init argv structure */
1319 argv.size=0;
1320 argv.argc=0;
1321 argv.argv=malloc(0); /*so we can call realloc later */
1322 addarg(&argv, "login");
1323 addarg(&argv, "-h");
1324 addarg(&argv, host);
1325 addarg(&argv, "-p");
1326 if(name[0])
1327 user = name;
1328 else
1329 user = getenv("USER");
1330 #ifdef AUTHENTICATION
1331 if (auth_level < 0 || autologin != AUTH_VALID) {
1332 if(!no_warn) {
1333 printf("User not authenticated. ");
1334 if (require_otp)
1335 printf("Using one-time password\r\n");
1336 else
1337 printf("Using plaintext username and password\r\n");
1339 if (require_otp) {
1340 addarg(&argv, "-a");
1341 addarg(&argv, "otp");
1343 if(log_unauth)
1344 syslog(LOG_INFO, "unauthenticated access from %s (%s)",
1345 host, user ? user : "unknown user");
1347 if (auth_level >= 0 && autologin == AUTH_VALID)
1348 addarg(&argv, "-f");
1349 #endif
1350 if(user){
1351 addarg(&argv, "--");
1352 addarg(&argv, strdup(user));
1354 if (getenv("USER")) {
1356 * Assume that login will set the USER variable
1357 * correctly. For SysV systems, this means that
1358 * USER will no longer be set, just LOGNAME by
1359 * login. (The problem is that if the auto-login
1360 * fails, and the user then specifies a different
1361 * account name, he can get logged in with both
1362 * LOGNAME and USER in his environment, but the
1363 * USER value will be wrong.
1365 unsetenv("USER");
1367 closelog();
1369 * This sleep(1) is in here so that telnetd can
1370 * finish up with the tty. There's a race condition
1371 * the login banner message gets lost...
1373 sleep(1);
1375 execv(new_login, argv.argv);
1376 save_errno = errno;
1377 syslog(LOG_ERR, "%s: %m", new_login);
1378 fatalperror_errno(net, new_login, save_errno);
1379 /*NOTREACHED*/
1382 static void
1383 addarg(struct arg_val *argv, const char *val)
1385 if(argv->size <= argv->argc+1) {
1386 argv->argv = realloc(argv->argv, sizeof(char*) * (argv->size + 10));
1387 if (argv->argv == NULL)
1388 fatal (net, "realloc: out of memory");
1389 argv->size+=10;
1391 if((argv->argv[argv->argc++] = strdup(val)) == NULL)
1392 fatal (net, "strdup: out of memory");
1393 argv->argv[argv->argc] = NULL;
1398 * rmut()
1400 * This is the function called by cleanup() to
1401 * remove the utmp entry for this person.
1404 #ifdef HAVE_UTMPX_H
1405 static void
1406 rmut(void)
1408 struct utmpx utmpx, *non_save_utxp;
1409 char *clean_tty = clean_ttyname(line);
1412 * This updates the utmpx and utmp entries and make a wtmp/x entry
1415 setutxent();
1416 memset(&utmpx, 0, sizeof(utmpx));
1417 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1418 utmpx.ut_type = LOGIN_PROCESS;
1419 non_save_utxp = getutxline(&utmpx);
1420 if (non_save_utxp) {
1421 struct utmpx *utxp;
1422 struct timeval tv;
1423 char user0;
1425 utxp = malloc(sizeof(struct utmpx));
1426 *utxp = *non_save_utxp;
1427 user0 = utxp->ut_user[0];
1428 utxp->ut_user[0] = '\0';
1429 utxp->ut_type = DEAD_PROCESS;
1430 #ifdef HAVE_STRUCT_UTMPX_UT_EXIT
1431 #ifdef _STRUCT___EXIT_STATUS
1432 utxp->ut_exit.__e_termination = 0;
1433 utxp->ut_exit.__e_exit = 0;
1434 #elif defined(__osf__) /* XXX */
1435 utxp->ut_exit.ut_termination = 0;
1436 utxp->ut_exit.ut_exit = 0;
1437 #else
1438 utxp->ut_exit.e_termination = 0;
1439 utxp->ut_exit.e_exit = 0;
1440 #endif
1441 #endif
1442 gettimeofday (&tv, NULL);
1443 utxp->ut_tv.tv_sec = tv.tv_sec;
1444 utxp->ut_tv.tv_usec = tv.tv_usec;
1446 pututxline(utxp);
1447 #ifdef WTMPX_FILE
1448 utxp->ut_user[0] = user0;
1449 updwtmpx(WTMPX_FILE, utxp);
1450 #elif defined(WTMP_FILE)
1451 /* This is a strange system with a utmpx and a wtmp! */
1453 int f = open(wtmpf, O_WRONLY|O_APPEND);
1454 struct utmp wtmp;
1455 if (f >= 0) {
1456 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));
1457 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));
1458 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1459 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));
1460 #endif
1461 wtmp.ut_time = time(NULL);
1462 write(f, &wtmp, sizeof(wtmp));
1463 close(f);
1466 #endif
1467 free (utxp);
1469 endutxent();
1470 } /* end of rmut */
1471 #endif
1473 #if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43
1474 static void
1475 rmut(void)
1477 int f;
1478 int found = 0;
1479 struct utmp *u, *utmp;
1480 int nutmp;
1481 struct stat statbf;
1482 char *clean_tty = clean_ttyname(line);
1484 f = open(utmpf, O_RDWR);
1485 if (f >= 0) {
1486 fstat(f, &statbf);
1487 utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
1488 if (!utmp)
1489 syslog(LOG_ERR, "utmp malloc failed");
1490 if (statbf.st_size && utmp) {
1491 nutmp = read(f, utmp, (int)statbf.st_size);
1492 nutmp /= sizeof(struct utmp);
1494 for (u = utmp ; u < &utmp[nutmp] ; u++) {
1495 if (strncmp(u->ut_line,
1496 clean_tty,
1497 sizeof(u->ut_line)) ||
1498 u->ut_name[0]==0)
1499 continue;
1500 lseek(f, ((long)u)-((long)utmp), L_SET);
1501 strncpy(u->ut_name, "", sizeof(u->ut_name));
1502 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1503 strncpy(u->ut_host, "", sizeof(u->ut_host));
1504 #endif
1505 u->ut_time = time(NULL);
1506 write(f, u, sizeof(wtmp));
1507 found++;
1510 close(f);
1512 if (found) {
1513 f = open(wtmpf, O_WRONLY|O_APPEND);
1514 if (f >= 0) {
1515 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));
1516 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));
1517 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1518 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));
1519 #endif
1520 wtmp.ut_time = time(NULL);
1521 write(f, &wtmp, sizeof(wtmp));
1522 close(f);
1525 chmod(line, 0666);
1526 chown(line, 0, 0);
1527 line[strlen("/dev/")] = 'p';
1528 chmod(line, 0666);
1529 chown(line, 0, 0);
1530 } /* end of rmut */
1531 #endif /* CRAY */
1533 #if defined(__hpux) && !defined(HAVE_UTMPX_H)
1534 static void
1535 rmut (char *line)
1537 struct utmp utmp;
1538 struct utmp *utptr;
1539 int fd; /* for /etc/wtmp */
1541 utmp.ut_type = USER_PROCESS;
1542 strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line));
1543 setutent();
1544 utptr = getutline(&utmp);
1545 /* write it out only if it exists */
1546 if (utptr) {
1547 utptr->ut_type = DEAD_PROCESS;
1548 utptr->ut_time = time(NULL);
1549 pututline(utptr);
1550 /* set wtmp entry if wtmp file exists */
1551 if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
1552 write(fd, utptr, sizeof(utmp));
1553 close(fd);
1556 endutent();
1558 chmod(line, 0666);
1559 chown(line, 0, 0);
1560 line[14] = line[13];
1561 line[13] = line[12];
1562 line[8] = 'm';
1563 line[9] = '/';
1564 line[10] = 'p';
1565 line[11] = 't';
1566 line[12] = 'y';
1567 chmod(line, 0666);
1568 chown(line, 0, 0);
1570 #endif
1573 * cleanup()
1575 * This is the routine to call when we are all through, to
1576 * clean up anything that needs to be cleaned up.
1579 #ifdef PARENT_DOES_UTMP
1581 void
1582 cleanup(int sig)
1584 #ifdef _CRAY
1585 static int incleanup = 0;
1586 int t;
1587 int child_status; /* status of child process as returned by waitpid */
1588 int flags = WNOHANG|WUNTRACED;
1591 * 1: Pick up the zombie, if we are being called
1592 * as the signal handler.
1593 * 2: If we are a nested cleanup(), return.
1594 * 3: Try to clean up TMPDIR.
1595 * 4: Fill in utmp with shutdown of process.
1596 * 5: Close down the network and pty connections.
1597 * 6: Finish up the TMPDIR cleanup, if needed.
1599 if (sig == SIGCHLD) {
1600 while (waitpid(-1, &child_status, flags) > 0)
1601 ; /* VOID */
1602 /* Check if the child process was stopped
1603 * rather than exited. We want cleanup only if
1604 * the child has died.
1606 if (WIFSTOPPED(child_status)) {
1607 return;
1610 t = sigblock(sigmask(SIGCHLD));
1611 if (incleanup) {
1612 sigsetmask(t);
1613 return;
1615 incleanup = 1;
1616 sigsetmask(t);
1618 t = cleantmp(&wtmp);
1619 setutent(); /* just to make sure */
1620 #endif /* CRAY */
1621 rmut(line);
1622 close(ourpty);
1623 shutdown(net, 2);
1624 #ifdef _CRAY
1625 if (t == 0)
1626 cleantmp(&wtmp);
1627 #endif /* CRAY */
1628 exit(1);
1631 #else /* PARENT_DOES_UTMP */
1633 void
1634 cleanup(int sig)
1636 #if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)
1637 rmut();
1638 #ifdef HAVE_VHANGUP
1639 #ifndef __sgi
1640 vhangup(); /* XXX */
1641 #endif
1642 #endif
1643 #else
1644 char *p;
1646 p = line + sizeof("/dev/") - 1;
1647 if (logout(p))
1648 logwtmp(p, "", "");
1649 chmod(line, 0666);
1650 chown(line, 0, 0);
1651 *p = 'p';
1652 chmod(line, 0666);
1653 chown(line, 0, 0);
1654 #endif
1655 shutdown(net, 2);
1656 exit(1);
1659 #endif /* PARENT_DOES_UTMP */
1661 #ifdef PARENT_DOES_UTMP
1663 * _utmp_sig_rcv
1664 * utmp_sig_init
1665 * utmp_sig_wait
1666 * These three functions are used to coordinate the handling of
1667 * the utmp file between the server and the soon-to-be-login shell.
1668 * The server actually creates the utmp structure, the child calls
1669 * utmp_sig_wait(), until the server calls utmp_sig_notify() and
1670 * signals the future-login shell to proceed.
1672 static int caught=0; /* NZ when signal intercepted */
1673 static void (*func)(); /* address of previous handler */
1675 void
1676 _utmp_sig_rcv(sig)
1677 int sig;
1679 caught = 1;
1680 signal(SIGUSR1, func);
1683 void
1684 utmp_sig_init()
1687 * register signal handler for UTMP creation
1689 if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1690 fatalperror(net, "telnetd/signal");
1693 void
1694 utmp_sig_reset()
1696 signal(SIGUSR1, func); /* reset handler to default */
1699 # ifdef __hpux
1700 # define sigoff() /* do nothing */
1701 # define sigon() /* do nothing */
1702 # endif
1704 void
1705 utmp_sig_wait()
1708 * Wait for parent to write our utmp entry.
1710 sigoff();
1711 while (caught == 0) {
1712 pause(); /* wait until we get a signal (sigon) */
1713 sigoff(); /* turn off signals while we check caught */
1715 sigon(); /* turn on signals again */
1718 void
1719 utmp_sig_notify(pid)
1721 kill(pid, SIGUSR1);
1724 #ifdef _CRAY
1725 static int gotsigjob = 0;
1727 /*ARGSUSED*/
1728 void
1729 sigjob(sig)
1730 int sig;
1732 int jid;
1733 struct jobtemp *jp;
1735 while ((jid = waitjob(NULL)) != -1) {
1736 if (jid == 0) {
1737 return;
1739 gotsigjob++;
1740 jobend(jid, NULL, NULL);
1745 * jid_getutid:
1746 * called by jobend() before calling cleantmp()
1747 * to find the correct $TMPDIR to cleanup.
1750 struct utmp *
1751 jid_getutid(jid)
1752 int jid;
1754 struct utmp *cur = NULL;
1756 setutent(); /* just to make sure */
1757 while (cur = getutent()) {
1758 if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
1759 return(cur);
1763 return(0);
1767 * Clean up the TMPDIR that login created.
1768 * The first time this is called we pick up the info
1769 * from the utmp. If the job has already gone away,
1770 * then we'll clean up and be done. If not, then
1771 * when this is called the second time it will wait
1772 * for the signal that the job is done.
1775 cleantmp(wtp)
1776 struct utmp *wtp;
1778 struct utmp *utp;
1779 static int first = 1;
1780 int mask, omask, ret;
1781 extern struct utmp *getutid (const struct utmp *_Id);
1784 mask = sigmask(WJSIGNAL);
1786 if (first == 0) {
1787 omask = sigblock(mask);
1788 while (gotsigjob == 0)
1789 sigpause(omask);
1790 return(1);
1792 first = 0;
1793 setutent(); /* just to make sure */
1795 utp = getutid(wtp);
1796 if (utp == 0) {
1797 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1798 return(-1);
1801 * Nothing to clean up if the user shell was never started.
1803 if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
1804 return(1);
1807 * Block the WJSIGNAL while we are in jobend().
1809 omask = sigblock(mask);
1810 ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
1811 sigsetmask(omask);
1812 return(ret);
1816 jobend(jid, path, user)
1817 int jid;
1818 char *path;
1819 char *user;
1821 static int saved_jid = 0;
1822 static int pty_saved_jid = 0;
1823 static char saved_path[sizeof(wtmp.ut_tpath)+1];
1824 static char saved_user[sizeof(wtmp.ut_user)+1];
1827 * this little piece of code comes into play
1828 * only when ptyreconnect is used to reconnect
1829 * to an previous session.
1831 * this is the only time when the
1832 * "saved_jid != jid" code is executed.
1835 if ( saved_jid && saved_jid != jid ) {
1836 if (!path) { /* called from signal handler */
1837 pty_saved_jid = jid;
1838 } else {
1839 pty_saved_jid = saved_jid;
1843 if (path) {
1844 strlcpy(saved_path, path, sizeof(saved_path));
1845 strlcpy(saved_user, user, sizeof(saved_user));
1847 if (saved_jid == 0) {
1848 saved_jid = jid;
1849 return(0);
1852 /* if the jid has changed, get the correct entry from the utmp file */
1854 if ( saved_jid != jid ) {
1855 struct utmp *utp = NULL;
1856 struct utmp *jid_getutid();
1858 utp = jid_getutid(pty_saved_jid);
1860 if (utp == 0) {
1861 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1862 return(-1);
1865 cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
1866 return(1);
1869 cleantmpdir(jid, saved_path, saved_user);
1870 return(1);
1874 * Fork a child process to clean up the TMPDIR
1876 cleantmpdir(jid, tpath, user)
1877 int jid;
1878 char *tpath;
1879 char *user;
1881 switch(fork()) {
1882 case -1:
1883 syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
1884 tpath);
1885 break;
1886 case 0:
1887 execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, NULL);
1888 syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1889 tpath, CLEANTMPCMD);
1890 exit(1);
1891 default:
1893 * Forget about child. We will exit, and
1894 * /etc/init will pick it up.
1896 break;
1899 #endif /* CRAY */
1900 #endif /* defined(PARENT_DOES_UTMP) */