Really, mac os uses wtmpx (or asl).
[heimdal.git] / appl / telnet / telnetd / sys_term.c
blob37c18ccd3816b30bc00eba199dc1a321381fe639
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 /* really, mac os uses wtmpx (or asl) */
71 #ifdef __APPLE__
72 #undef _PATH_WTMP
73 #endif
75 #if !defined(WTMP_FILE) && defined(_PATH_WTMP)
76 #define WTMP_FILE _PATH_WTMP
77 #endif
79 #ifndef PARENT_DOES_UTMP
80 #ifdef WTMP_FILE
81 char wtmpf[] = WTMP_FILE;
82 #else
83 char wtmpf[] = "/usr/adm/wtmp";
84 #endif
85 char utmpf[] = UTMP_FILE;
86 #else /* PARENT_DOES_UTMP */
87 #ifdef WTMP_FILE
88 char wtmpf[] = WTMP_FILE;
89 #else
90 char wtmpf[] = "/etc/wtmp";
91 #endif
92 #endif /* PARENT_DOES_UTMP */
94 #ifdef HAVE_TMPDIR_H
95 #include <tmpdir.h>
96 #endif /* CRAY */
98 #if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY)
99 #include <sys/tty.h>
100 #endif
101 #ifdef t_erase
102 #undef t_erase
103 #undef t_kill
104 #undef t_intrc
105 #undef t_quitc
106 #undef t_startc
107 #undef t_stopc
108 #undef t_eofc
109 #undef t_brkc
110 #undef t_suspc
111 #undef t_dsuspc
112 #undef t_rprntc
113 #undef t_flushc
114 #undef t_werasc
115 #undef t_lnextc
116 #endif
118 #ifdef HAVE_TERMIOS_H
119 #include <termios.h>
120 #else
121 #ifdef HAVE_TERMIO_H
122 #include <termio.h>
123 #endif
124 #endif
126 #ifdef HAVE_UTIL_H
127 #include <util.h>
128 #endif
129 #ifdef HAVE_LIBUTIL_H
130 #include <libutil.h>
131 #endif
133 # ifndef TCSANOW
134 # ifdef TCSETS
135 # define TCSANOW TCSETS
136 # define TCSADRAIN TCSETSW
137 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
138 # else
139 # ifdef TCSETA
140 # define TCSANOW TCSETA
141 # define TCSADRAIN TCSETAW
142 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
143 # else
144 # define TCSANOW TIOCSETA
145 # define TCSADRAIN TIOCSETAW
146 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
147 # endif
148 # endif
149 # define tcsetattr(f, a, t) ioctl(f, a, t)
150 # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
151 (tp)->c_cflag |= (val)
152 # define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
153 # ifdef CIBAUD
154 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
155 (tp)->c_cflag |= ((val)<<IBSHIFT)
156 # define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
157 # else
158 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
159 (tp)->c_cflag |= (val)
160 # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
161 # endif
162 # endif /* TCSANOW */
163 struct termios termbuf, termbuf2; /* pty control structure */
164 # ifdef STREAMSPTY
165 static int ttyfd = -1;
166 int really_stream = 0;
167 # else
168 #define really_stream 0
169 # endif
171 const char *new_login = _PATH_LOGIN;
174 * init_termbuf()
175 * copy_termbuf(cp)
176 * set_termbuf()
178 * These three routines are used to get and set the "termbuf" structure
179 * to and from the kernel. init_termbuf() gets the current settings.
180 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
181 * set_termbuf() writes the structure into the kernel.
184 void
185 init_termbuf(void)
187 # ifdef STREAMSPTY
188 if (really_stream)
189 tcgetattr(ttyfd, &termbuf);
190 else
191 # endif
192 tcgetattr(ourpty, &termbuf);
193 termbuf2 = termbuf;
196 void
197 set_termbuf(void)
200 * Only make the necessary changes.
202 if (memcmp(&termbuf, &termbuf2, sizeof(termbuf))) {
203 # ifdef STREAMSPTY
204 if (really_stream)
205 tcsetattr(ttyfd, TCSANOW, &termbuf);
206 else
207 # endif
208 tcsetattr(ourpty, TCSANOW, &termbuf);
214 * spcset(func, valp, valpp)
216 * This function takes various special characters (func), and
217 * sets *valp to the current value of that character, and
218 * *valpp to point to where in the "termbuf" structure that
219 * value is kept.
221 * It returns the SLC_ level of support for this function.
226 spcset(int func, cc_t *valp, cc_t **valpp)
229 #define setval(a, b) *valp = termbuf.c_cc[a]; \
230 *valpp = &termbuf.c_cc[a]; \
231 return(b);
232 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
234 switch(func) {
235 case SLC_EOF:
236 setval(VEOF, SLC_VARIABLE);
237 case SLC_EC:
238 setval(VERASE, SLC_VARIABLE);
239 case SLC_EL:
240 setval(VKILL, SLC_VARIABLE);
241 case SLC_IP:
242 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
243 case SLC_ABORT:
244 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
245 case SLC_XON:
246 #ifdef VSTART
247 setval(VSTART, SLC_VARIABLE);
248 #else
249 defval(0x13);
250 #endif
251 case SLC_XOFF:
252 #ifdef VSTOP
253 setval(VSTOP, SLC_VARIABLE);
254 #else
255 defval(0x11);
256 #endif
257 case SLC_EW:
258 #ifdef VWERASE
259 setval(VWERASE, SLC_VARIABLE);
260 #else
261 defval(0);
262 #endif
263 case SLC_RP:
264 #ifdef VREPRINT
265 setval(VREPRINT, SLC_VARIABLE);
266 #else
267 defval(0);
268 #endif
269 case SLC_LNEXT:
270 #ifdef VLNEXT
271 setval(VLNEXT, SLC_VARIABLE);
272 #else
273 defval(0);
274 #endif
275 case SLC_AO:
276 #if !defined(VDISCARD) && defined(VFLUSHO)
277 # define VDISCARD VFLUSHO
278 #endif
279 #ifdef VDISCARD
280 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
281 #else
282 defval(0);
283 #endif
284 case SLC_SUSP:
285 #ifdef VSUSP
286 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
287 #else
288 defval(0);
289 #endif
290 #ifdef VEOL
291 case SLC_FORW1:
292 setval(VEOL, SLC_VARIABLE);
293 #endif
294 #ifdef VEOL2
295 case SLC_FORW2:
296 setval(VEOL2, SLC_VARIABLE);
297 #endif
298 case SLC_AYT:
299 #ifdef VSTATUS
300 setval(VSTATUS, SLC_VARIABLE);
301 #else
302 defval(0);
303 #endif
305 case SLC_BRK:
306 case SLC_SYNCH:
307 case SLC_EOR:
308 defval(0);
310 default:
311 *valp = 0;
312 *valpp = 0;
313 return(SLC_NOSUPPORT);
317 #ifdef _CRAY
319 * getnpty()
321 * Return the number of pty's configured into the system.
324 getnpty()
326 #ifdef _SC_CRAY_NPTY
327 int numptys;
329 if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
330 return numptys;
331 else
332 #endif /* _SC_CRAY_NPTY */
333 return 128;
335 #endif /* CRAY */
338 * getpty()
340 * Allocate a pty. As a side effect, the external character
341 * array "line" contains the name of the slave side.
343 * Returns the file descriptor of the opened pty.
346 static int ptyslavefd = -1;
348 static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
349 char *line = Xline;
351 #ifdef _CRAY
352 char myline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
353 #endif /* CRAY */
355 #if !defined(HAVE_PTSNAME) && defined(STREAMSPTY)
356 static char *ptsname(int fd)
358 #ifdef HAVE_TTYNAME
359 return ttyname(fd);
360 #else
361 return NULL;
362 #endif
364 #endif
366 int getpty(int *ptynum)
368 #if defined(HAVE_OPENPTY) || defined(__linux) || defined(__osf__) /* XXX */
370 int master;
371 int slave;
372 if(openpty(&master, &slave, line, 0, 0) == 0){
373 ptyslavefd = slave;
374 return master;
377 #endif /* HAVE_OPENPTY .... */
378 #ifdef HAVE__GETPTY
380 int master;
381 char *p;
382 p = _getpty(&master, O_RDWR, 0600, 1);
383 if(p == NULL)
384 return -1;
385 strlcpy(line, p, sizeof(Xline));
386 return master;
388 #endif
390 #ifdef STREAMSPTY
392 char *clone[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm",
393 "/dev/ptym/clone", 0 };
395 char **q;
396 int p;
397 for(q=clone; *q; q++){
398 p=open(*q, O_RDWR);
399 if(p >= 0){
400 #ifdef HAVE_GRANTPT
401 grantpt(p);
402 #endif
403 #ifdef HAVE_UNLOCKPT
404 unlockpt(p);
405 #endif
406 strlcpy(line, ptsname(p), sizeof(Xline));
407 really_stream = 1;
408 return p;
412 #endif /* STREAMSPTY */
413 #ifndef _CRAY
415 int p;
416 char *cp, *p1, *p2;
417 int i;
419 #ifndef __hpux
420 snprintf(line, sizeof(Xline), "/dev/ptyXX");
421 p1 = &line[8];
422 p2 = &line[9];
423 #else
424 snprintf(line, sizeof(Xline), "/dev/ptym/ptyXX");
425 p1 = &line[13];
426 p2 = &line[14];
427 #endif
430 for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
431 struct stat stb;
433 *p1 = *cp;
434 *p2 = '0';
436 * This stat() check is just to keep us from
437 * looping through all 256 combinations if there
438 * aren't that many ptys available.
440 if (stat(line, &stb) < 0)
441 break;
442 for (i = 0; i < 16; i++) {
443 *p2 = "0123456789abcdef"[i];
444 p = open(line, O_RDWR);
445 if (p > 0) {
446 #if SunOS == 40
447 int dummy;
448 #endif
450 #ifndef __hpux
451 line[5] = 't';
452 #else
453 for (p1 = &line[8]; *p1; p1++)
454 *p1 = *(p1+1);
455 line[9] = 't';
456 #endif
457 chown(line, 0, 0);
458 chmod(line, 0600);
459 #if SunOS == 40
460 if (ioctl(p, TIOCGPGRP, &dummy) == 0
461 || errno != EIO) {
462 chmod(line, 0666);
463 close(p);
464 line[5] = 'p';
465 } else
466 #endif /* SunOS == 40 */
467 return(p);
472 #else /* CRAY */
474 extern lowpty, highpty;
475 struct stat sb;
476 int p;
478 for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {
479 snprintf(myline, sizeof(myline), "/dev/pty/%03d", *ptynum);
480 p = open(myline, 2);
481 if (p < 0)
482 continue;
483 snprintf(line, sizeof(Xline), "/dev/ttyp%03d", *ptynum);
485 * Here are some shenanigans to make sure that there
486 * are no listeners lurking on the line.
488 if(stat(line, &sb) < 0) {
489 close(p);
490 continue;
492 if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
493 chown(line, 0, 0);
494 chmod(line, 0600);
495 close(p);
496 p = open(myline, 2);
497 if (p < 0)
498 continue;
501 * Now it should be safe...check for accessability.
503 if (access(line, 6) == 0)
504 return(p);
505 else {
506 /* no tty side to pty so skip it */
507 close(p);
511 #endif /* CRAY */
512 return(-1);
517 tty_isecho(void)
519 return (termbuf.c_lflag & ECHO);
523 tty_flowmode(void)
525 return((termbuf.c_iflag & IXON) ? 1 : 0);
529 tty_restartany(void)
531 return((termbuf.c_iflag & IXANY) ? 1 : 0);
534 void
535 tty_setecho(int on)
537 if (on)
538 termbuf.c_lflag |= ECHO;
539 else
540 termbuf.c_lflag &= ~ECHO;
544 tty_israw(void)
546 return(!(termbuf.c_lflag & ICANON));
549 void
550 tty_binaryin(int on)
552 if (on) {
553 termbuf.c_iflag &= ~ISTRIP;
554 } else {
555 termbuf.c_iflag |= ISTRIP;
559 void
560 tty_binaryout(int on)
562 if (on) {
563 termbuf.c_cflag &= ~(CSIZE|PARENB);
564 termbuf.c_cflag |= CS8;
565 termbuf.c_oflag &= ~OPOST;
566 } else {
567 termbuf.c_cflag &= ~CSIZE;
568 termbuf.c_cflag |= CS7|PARENB;
569 termbuf.c_oflag |= OPOST;
574 tty_isbinaryin(void)
576 return(!(termbuf.c_iflag & ISTRIP));
580 tty_isbinaryout(void)
582 return(!(termbuf.c_oflag&OPOST));
587 tty_issofttab(void)
589 # ifdef OXTABS
590 return (termbuf.c_oflag & OXTABS);
591 # endif
592 # ifdef TABDLY
593 return ((termbuf.c_oflag & TABDLY) == TAB3);
594 # endif
597 void
598 tty_setsofttab(int on)
600 if (on) {
601 # ifdef OXTABS
602 termbuf.c_oflag |= OXTABS;
603 # endif
604 # ifdef TABDLY
605 termbuf.c_oflag &= ~TABDLY;
606 termbuf.c_oflag |= TAB3;
607 # endif
608 } else {
609 # ifdef OXTABS
610 termbuf.c_oflag &= ~OXTABS;
611 # endif
612 # ifdef TABDLY
613 termbuf.c_oflag &= ~TABDLY;
614 termbuf.c_oflag |= TAB0;
615 # endif
620 tty_islitecho(void)
622 # ifdef ECHOCTL
623 return (!(termbuf.c_lflag & ECHOCTL));
624 # endif
625 # ifdef TCTLECH
626 return (!(termbuf.c_lflag & TCTLECH));
627 # endif
628 # if !defined(ECHOCTL) && !defined(TCTLECH)
629 return (0); /* assumes ctl chars are echoed '^x' */
630 # endif
633 void
634 tty_setlitecho(int on)
636 # ifdef ECHOCTL
637 if (on)
638 termbuf.c_lflag &= ~ECHOCTL;
639 else
640 termbuf.c_lflag |= ECHOCTL;
641 # endif
642 # ifdef TCTLECH
643 if (on)
644 termbuf.c_lflag &= ~TCTLECH;
645 else
646 termbuf.c_lflag |= TCTLECH;
647 # endif
651 tty_iscrnl(void)
653 return (termbuf.c_iflag & ICRNL);
657 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
659 #if B4800 != 4800
660 #define DECODE_BAUD
661 #endif
663 #ifdef DECODE_BAUD
666 * A table of available terminal speeds
668 struct termspeeds {
669 int speed;
670 int value;
671 } termspeeds[] = {
672 { 0, B0 }, { 50, B50 }, { 75, B75 },
673 { 110, B110 }, { 134, B134 }, { 150, B150 },
674 { 200, B200 }, { 300, B300 }, { 600, B600 },
675 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
676 { 4800, B4800 },
677 #ifdef B7200
678 { 7200, B7200 },
679 #endif
680 { 9600, B9600 },
681 #ifdef B14400
682 { 14400, B14400 },
683 #endif
684 #ifdef B19200
685 { 19200, B19200 },
686 #endif
687 #ifdef B28800
688 { 28800, B28800 },
689 #endif
690 #ifdef B38400
691 { 38400, B38400 },
692 #endif
693 #ifdef B57600
694 { 57600, B57600 },
695 #endif
696 #ifdef B115200
697 { 115200, B115200 },
698 #endif
699 #ifdef B230400
700 { 230400, B230400 },
701 #endif
702 { -1, 0 }
704 #endif /* DECODE_BUAD */
706 void
707 tty_tspeed(int val)
709 #ifdef DECODE_BAUD
710 struct termspeeds *tp;
712 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
714 if (tp->speed == -1) /* back up to last valid value */
715 --tp;
716 cfsetospeed(&termbuf, tp->value);
717 #else /* DECODE_BUAD */
718 cfsetospeed(&termbuf, val);
719 #endif /* DECODE_BUAD */
722 void
723 tty_rspeed(int val)
725 #ifdef DECODE_BAUD
726 struct termspeeds *tp;
728 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
730 if (tp->speed == -1) /* back up to last valid value */
731 --tp;
732 cfsetispeed(&termbuf, tp->value);
733 #else /* DECODE_BAUD */
734 cfsetispeed(&termbuf, val);
735 #endif /* DECODE_BAUD */
738 #ifdef PARENT_DOES_UTMP
739 extern struct utmp wtmp;
740 extern char wtmpf[];
742 extern void utmp_sig_init (void);
743 extern void utmp_sig_reset (void);
744 extern void utmp_sig_wait (void);
745 extern void utmp_sig_notify (int);
746 # endif /* PARENT_DOES_UTMP */
748 #ifdef STREAMSPTY
750 /* I_FIND seems to live a life of its own */
751 static int my_find(int fd, char *module)
753 #if defined(I_FIND) && defined(I_LIST)
754 static int flag;
755 static struct str_list sl;
756 int n;
757 int i;
759 if(!flag){
760 n = ioctl(fd, I_LIST, 0);
761 if(n < 0){
762 perror("ioctl(fd, I_LIST, 0)");
763 return -1;
765 sl.sl_modlist=(struct str_mlist*)malloc(n * sizeof(struct str_mlist));
766 sl.sl_nmods = n;
767 n = ioctl(fd, I_LIST, &sl);
768 if(n < 0){
769 perror("ioctl(fd, I_LIST, n)");
770 return -1;
772 flag = 1;
775 for(i=0; i<sl.sl_nmods; i++)
776 if(!strcmp(sl.sl_modlist[i].l_name, module))
777 return 1;
778 #endif
779 return 0;
782 static void maybe_push_modules(int fd, char **modules)
784 char **p;
785 int err;
787 for(p=modules; *p; p++){
788 err = my_find(fd, *p);
789 if(err == 1)
790 break;
791 if(err < 0 && errno != EINVAL)
792 fatalperror(net, "my_find()");
793 /* module not pushed or does not exist */
795 /* p points to null or to an already pushed module, now push all
796 modules before this one */
798 for(p--; p >= modules; p--){
799 err = ioctl(fd, I_PUSH, *p);
800 if(err < 0 && errno != EINVAL)
801 fatalperror(net, "I_PUSH");
804 #endif
807 * getptyslave()
809 * Open the slave side of the pty, and do any initialization
810 * that is necessary. The return value is a file descriptor
811 * for the slave side.
813 void getptyslave(void)
815 int t = -1;
817 struct winsize ws;
819 * Opening the slave side may cause initilization of the
820 * kernel tty structure. We need remember the state of
821 * if linemode was turned on
822 * terminal window size
823 * terminal speed
824 * so that we can re-set them if we need to.
829 * Make sure that we don't have a controlling tty, and
830 * that we are the session (process group) leader.
833 #ifdef HAVE_SETSID
834 if(setsid()<0)
835 fatalperror(net, "setsid()");
836 #else
837 # ifdef TIOCNOTTY
838 t = open(_PATH_TTY, O_RDWR);
839 if (t >= 0) {
840 ioctl(t, TIOCNOTTY, (char *)0);
841 close(t);
843 # endif
844 #endif
846 # ifdef PARENT_DOES_UTMP
848 * Wait for our parent to get the utmp stuff to get done.
850 utmp_sig_wait();
851 # endif
853 t = cleanopen(line);
854 if (t < 0)
855 fatalperror(net, line);
857 #ifdef STREAMSPTY
858 ttyfd = t;
862 * Not all systems have (or need) modules ttcompat and pckt so
863 * don't flag it as a fatal error if they don't exist.
866 if (really_stream)
868 /* these are the streams modules that we want pushed. note
869 that they are in reverse order, ptem will be pushed
870 first. maybe_push_modules() will try to push all modules
871 before the first one that isn't already pushed. i.e if
872 ldterm is pushed, only ttcompat will be attempted.
874 all this is because we don't know which modules are
875 available, and we don't know which modules are already
876 pushed (via autopush, for instance).
880 char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL };
881 char *ptymodules[] = { "pckt", NULL };
883 maybe_push_modules(t, ttymodules);
884 maybe_push_modules(ourpty, ptymodules);
886 #endif
888 * set up the tty modes as we like them to be.
890 init_termbuf();
891 # ifdef TIOCSWINSZ
892 if (def_row || def_col) {
893 memset(&ws, 0, sizeof(ws));
894 ws.ws_col = def_col;
895 ws.ws_row = def_row;
896 ioctl(t, TIOCSWINSZ, (char *)&ws);
898 # endif
901 * Settings for sgtty based systems
905 * Settings for UNICOS (and HPUX)
907 # if defined(_CRAY) || defined(__hpux)
908 termbuf.c_oflag = OPOST|ONLCR|TAB3;
909 termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
910 termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
911 termbuf.c_cflag = EXTB|HUPCL|CS8;
912 # endif
915 * Settings for all other termios/termio based
916 * systems, other than 4.4BSD. In 4.4BSD the
917 * kernel does the initial terminal setup.
919 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43)
920 # ifndef OXTABS
921 # define OXTABS 0
922 # endif
923 termbuf.c_lflag |= ECHO;
924 termbuf.c_oflag |= ONLCR|OXTABS;
925 termbuf.c_iflag |= ICRNL;
926 termbuf.c_iflag &= ~IXOFF;
927 # endif
928 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
929 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
932 * Set the tty modes, and make this our controlling tty.
934 set_termbuf();
935 if (login_tty(t) == -1)
936 fatalperror(net, "login_tty");
937 if (net > 2)
938 close(net);
939 if (ourpty > 2) {
940 close(ourpty);
941 ourpty = -1;
945 #ifndef O_NOCTTY
946 #define O_NOCTTY 0
947 #endif
949 * Open the specified slave side of the pty,
950 * making sure that we have a clean tty.
953 int cleanopen(char *line)
955 int t;
957 if (ptyslavefd != -1)
958 return ptyslavefd;
960 #ifdef STREAMSPTY
961 if (!really_stream)
962 #endif
965 * Make sure that other people can't open the
966 * slave side of the connection.
968 chown(line, 0, 0);
969 chmod(line, 0600);
972 #ifdef HAVE_REVOKE
973 revoke(line);
974 #endif
976 t = open(line, O_RDWR|O_NOCTTY);
978 if (t < 0)
979 return(-1);
982 * Hangup anybody else using this ttyp, then reopen it for
983 * ourselves.
985 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
986 signal(SIGHUP, SIG_IGN);
987 #ifdef HAVE_VHANGUP
988 vhangup();
989 #else
990 #endif
991 signal(SIGHUP, SIG_DFL);
992 t = open(line, O_RDWR|O_NOCTTY);
993 if (t < 0)
994 return(-1);
995 # endif
996 # if defined(_CRAY) && defined(TCVHUP)
998 int i;
999 signal(SIGHUP, SIG_IGN);
1000 ioctl(t, TCVHUP, (char *)0);
1001 signal(SIGHUP, SIG_DFL);
1003 i = open(line, O_RDWR);
1005 if (i < 0)
1006 return(-1);
1007 close(t);
1008 t = i;
1010 # endif /* defined(CRAY) && defined(TCVHUP) */
1011 return(t);
1014 #if !defined(BSD4_4)
1016 int login_tty(int t)
1018 /* Dont need to set this as the controlling PTY on steams sockets,
1019 * don't abort on failure. */
1020 # if defined(TIOCSCTTY) && !defined(__hpux)
1021 if (ioctl(t, TIOCSCTTY, (char *)0) < 0 && !really_stream)
1022 fatalperror(net, "ioctl(sctty)");
1023 # ifdef _CRAY
1025 * Close the hard fd to /dev/ttypXXX, and re-open through
1026 * the indirect /dev/tty interface.
1028 close(t);
1029 if ((t = open("/dev/tty", O_RDWR)) < 0)
1030 fatalperror(net, "open(/dev/tty)");
1031 # endif
1032 # else
1034 * We get our controlling tty assigned as a side-effect
1035 * of opening up a tty device. But on BSD based systems,
1036 * this only happens if our process group is zero. The
1037 * setsid() call above may have set our pgrp, so clear
1038 * it out before opening the tty...
1040 #ifdef HAVE_SETPGID
1041 setpgid(0, 0);
1042 #else
1043 setpgrp(0, 0); /* if setpgid isn't available, setpgrp
1044 probably takes arguments */
1045 #endif
1046 close(open(line, O_RDWR));
1047 # endif
1048 if (t != 0)
1049 dup2(t, 0);
1050 if (t != 1)
1051 dup2(t, 1);
1052 if (t != 2)
1053 dup2(t, 2);
1054 if (t > 2)
1055 close(t);
1056 return(0);
1058 #endif /* BSD <= 43 */
1061 * This comes from ../../bsd/tty.c and should not really be here.
1065 * Clean the tty name. Return a pointer to the cleaned version.
1068 static char * clean_ttyname (char *) __attribute__((unused));
1070 static char *
1071 clean_ttyname (char *tty)
1073 char *res = tty;
1075 if (strncmp (res, _PATH_DEV, strlen(_PATH_DEV)) == 0)
1076 res += strlen(_PATH_DEV);
1077 if (strncmp (res, "pty/", 4) == 0)
1078 res += 4;
1079 if (strncmp (res, "ptym/", 5) == 0)
1080 res += 5;
1081 return res;
1085 * Generate a name usable as an `ut_id', typically without `tty'.
1088 #ifdef HAVE_STRUCT_UTMP_UT_ID
1089 static char *
1090 make_id (char *tty)
1092 char *res = tty;
1094 if (strncmp (res, "pts/", 4) == 0)
1095 res += 4;
1096 if (strncmp (res, "tty", 3) == 0)
1097 res += 3;
1098 return res;
1100 #endif
1103 * startslave(host)
1105 * Given a hostname, do whatever
1106 * is necessary to startup the login process on the slave side of the pty.
1109 /* ARGSUSED */
1110 void
1111 startslave(const char *host, const char *utmp_host,
1112 int autologin, char *autoname)
1114 int i;
1116 #ifdef AUTHENTICATION
1117 if (!autoname || !autoname[0])
1118 autologin = 0;
1120 if (autologin < auth_level) {
1121 fatal(net, "Authorization failed");
1122 exit(1);
1124 #endif
1127 char *tbuf =
1128 "\r\n*** Connection not encrypted! "
1129 "Communication may be eavesdropped. ***\r\n";
1130 #ifdef ENCRYPTION
1131 if (!no_warn && (encrypt_output == 0 || decrypt_input == 0))
1132 #endif
1133 writenet(tbuf, strlen(tbuf));
1135 # ifdef PARENT_DOES_UTMP
1136 utmp_sig_init();
1137 # endif /* PARENT_DOES_UTMP */
1139 if ((i = fork()) < 0)
1140 fatalperror(net, "fork");
1141 if (i) {
1142 # ifdef PARENT_DOES_UTMP
1144 * Cray parent will create utmp entry for child and send
1145 * signal to child to tell when done. Child waits for signal
1146 * before doing anything important.
1148 int pid = i;
1149 void sigjob (int);
1151 setpgrp();
1152 utmp_sig_reset(); /* reset handler to default */
1154 * Create utmp entry for child
1156 wtmp.ut_time = time(NULL);
1157 wtmp.ut_type = LOGIN_PROCESS;
1158 wtmp.ut_pid = pid;
1159 strncpy(wtmp.ut_user, "LOGIN", sizeof(wtmp.ut_user));
1160 strncpy(wtmp.ut_host, utmp_host, sizeof(wtmp.ut_host));
1161 strncpy(wtmp.ut_line, clean_ttyname(line), sizeof(wtmp.ut_line));
1162 #ifdef HAVE_STRUCT_UTMP_UT_ID
1163 strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id));
1164 #endif
1166 pututline(&wtmp);
1167 endutent();
1168 if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
1169 write(i, &wtmp, sizeof(struct utmp));
1170 close(i);
1172 #ifdef _CRAY
1173 signal(WJSIGNAL, sigjob);
1174 #endif
1175 utmp_sig_notify(pid);
1176 # endif /* PARENT_DOES_UTMP */
1177 } else {
1178 getptyslave();
1179 #if defined(DCE)
1180 /* if we authenticated via K5, try and join the PAG */
1181 kerberos5_dfspag();
1182 #endif
1183 start_login(host, autologin, autoname);
1184 /*NOTREACHED*/
1188 char *envinit[3];
1189 extern char **environ;
1191 void
1192 init_env(void)
1194 char **envp;
1196 envp = envinit;
1197 if ((*envp = getenv("TZ")))
1198 *envp++ -= 3;
1199 #if defined(_CRAY) || defined(__hpux)
1200 else
1201 *envp++ = "TZ=GMT0";
1202 #endif
1203 *envp = 0;
1204 environ = envinit;
1208 * scrub_env()
1210 * We only accept the environment variables listed below.
1213 static void
1214 scrub_env(void)
1216 static const char *reject[] = {
1217 "TERMCAP=/",
1218 NULL
1221 static const char *accept[] = {
1222 "XAUTH=", "XAUTHORITY=", "DISPLAY=",
1223 "TERM=",
1224 "EDITOR=",
1225 "PAGER=",
1226 "PRINTER=",
1227 "LOGNAME=",
1228 "POSIXLY_CORRECT=",
1229 "TERMCAP=",
1230 NULL
1233 char **cpp, **cpp2;
1234 const char **p;
1236 for (cpp2 = cpp = environ; *cpp; cpp++) {
1237 int reject_it = 0;
1239 for(p = reject; *p; p++)
1240 if(strncmp(*cpp, *p, strlen(*p)) == 0) {
1241 reject_it = 1;
1242 break;
1244 if (reject_it)
1245 continue;
1247 for(p = accept; *p; p++)
1248 if(strncmp(*cpp, *p, strlen(*p)) == 0)
1249 break;
1250 if(*p != NULL)
1251 *cpp2++ = *cpp;
1253 *cpp2 = NULL;
1257 struct arg_val {
1258 int size;
1259 int argc;
1260 char **argv;
1263 static void addarg(struct arg_val*, const char*);
1266 * start_login(host)
1268 * Assuming that we are now running as a child processes, this
1269 * function will turn us into the login process.
1272 void
1273 start_login(const char *host, int autologin, char *name)
1275 struct arg_val argv;
1276 char *user;
1277 int save_errno;
1279 #ifdef ENCRYPTION
1280 encrypt_output = NULL;
1281 decrypt_input = NULL;
1282 #endif
1284 #ifdef HAVE_UTMPX_H
1286 int pid = getpid();
1287 struct utmpx utmpx;
1288 struct timeval tv;
1289 char *clean_tty;
1292 * Create utmp entry for child
1295 clean_tty = clean_ttyname(line);
1296 memset(&utmpx, 0, sizeof(utmpx));
1297 strncpy(utmpx.ut_user, ".telnet", sizeof(utmpx.ut_user));
1298 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1299 #ifdef HAVE_STRUCT_UTMP_UT_ID
1300 strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id));
1301 #endif
1302 utmpx.ut_pid = pid;
1304 utmpx.ut_type = LOGIN_PROCESS;
1306 gettimeofday (&tv, NULL);
1307 utmpx.ut_tv.tv_sec = tv.tv_sec;
1308 utmpx.ut_tv.tv_usec = tv.tv_usec;
1310 if (pututxline(&utmpx) == NULL)
1311 fatal(net, "pututxline failed");
1313 #endif
1315 scrub_env();
1318 * -h : pass on name of host.
1319 * WARNING: -h is accepted by login if and only if
1320 * getuid() == 0.
1321 * -p : don't clobber the environment (so terminal type stays set).
1323 * -f : force this login, he has already been authenticated
1326 /* init argv structure */
1327 argv.size=0;
1328 argv.argc=0;
1329 argv.argv=malloc(0); /*so we can call realloc later */
1330 addarg(&argv, "login");
1331 addarg(&argv, "-h");
1332 addarg(&argv, host);
1333 addarg(&argv, "-p");
1334 if(name[0])
1335 user = name;
1336 else
1337 user = getenv("USER");
1338 #ifdef AUTHENTICATION
1339 if (auth_level < 0 || autologin != AUTH_VALID) {
1340 if(!no_warn) {
1341 printf("User not authenticated. ");
1342 if (require_otp)
1343 printf("Using one-time password\r\n");
1344 else
1345 printf("Using plaintext username and password\r\n");
1347 if (require_otp) {
1348 addarg(&argv, "-a");
1349 addarg(&argv, "otp");
1351 if(log_unauth)
1352 syslog(LOG_INFO, "unauthenticated access from %s (%s)",
1353 host, user ? user : "unknown user");
1355 if (auth_level >= 0 && autologin == AUTH_VALID)
1356 addarg(&argv, "-f");
1357 #endif
1358 if(user){
1359 addarg(&argv, "--");
1360 addarg(&argv, strdup(user));
1362 if (getenv("USER")) {
1364 * Assume that login will set the USER variable
1365 * correctly. For SysV systems, this means that
1366 * USER will no longer be set, just LOGNAME by
1367 * login. (The problem is that if the auto-login
1368 * fails, and the user then specifies a different
1369 * account name, he can get logged in with both
1370 * LOGNAME and USER in his environment, but the
1371 * USER value will be wrong.
1373 unsetenv("USER");
1375 closelog();
1377 * This sleep(1) is in here so that telnetd can
1378 * finish up with the tty. There's a race condition
1379 * the login banner message gets lost...
1381 sleep(1);
1383 execv(new_login, argv.argv);
1384 save_errno = errno;
1385 syslog(LOG_ERR, "%s: %m", new_login);
1386 fatalperror_errno(net, new_login, save_errno);
1387 /*NOTREACHED*/
1390 static void
1391 addarg(struct arg_val *argv, const char *val)
1393 if(argv->size <= argv->argc+1) {
1394 argv->argv = realloc(argv->argv, sizeof(char*) * (argv->size + 10));
1395 if (argv->argv == NULL)
1396 fatal (net, "realloc: out of memory");
1397 argv->size+=10;
1399 if((argv->argv[argv->argc++] = strdup(val)) == NULL)
1400 fatal (net, "strdup: out of memory");
1401 argv->argv[argv->argc] = NULL;
1406 * rmut()
1408 * This is the function called by cleanup() to
1409 * remove the utmp entry for this person.
1412 #ifdef HAVE_UTMPX_H
1413 static void
1414 rmut(void)
1416 struct utmpx utmpx, *non_save_utxp;
1417 char *clean_tty = clean_ttyname(line);
1420 * This updates the utmpx and utmp entries and make a wtmp/x entry
1423 setutxent();
1424 memset(&utmpx, 0, sizeof(utmpx));
1425 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1426 utmpx.ut_type = LOGIN_PROCESS;
1427 non_save_utxp = getutxline(&utmpx);
1428 if (non_save_utxp) {
1429 struct utmpx *utxp;
1430 struct timeval tv;
1431 char user0;
1433 utxp = malloc(sizeof(struct utmpx));
1434 *utxp = *non_save_utxp;
1435 user0 = utxp->ut_user[0];
1436 utxp->ut_user[0] = '\0';
1437 utxp->ut_type = DEAD_PROCESS;
1438 #ifdef HAVE_STRUCT_UTMPX_UT_EXIT
1439 #ifdef _STRUCT___EXIT_STATUS
1440 utxp->ut_exit.__e_termination = 0;
1441 utxp->ut_exit.__e_exit = 0;
1442 #elif defined(__osf__) /* XXX */
1443 utxp->ut_exit.ut_termination = 0;
1444 utxp->ut_exit.ut_exit = 0;
1445 #else
1446 utxp->ut_exit.e_termination = 0;
1447 utxp->ut_exit.e_exit = 0;
1448 #endif
1449 #endif
1450 gettimeofday (&tv, NULL);
1451 utxp->ut_tv.tv_sec = tv.tv_sec;
1452 utxp->ut_tv.tv_usec = tv.tv_usec;
1454 pututxline(utxp);
1455 #ifdef WTMPX_FILE
1456 utxp->ut_user[0] = user0;
1457 updwtmpx(WTMPX_FILE, utxp);
1458 #elif defined(WTMP_FILE)
1459 /* This is a strange system with a utmpx and a wtmp! */
1461 int f = open(wtmpf, O_WRONLY|O_APPEND);
1462 struct utmp wtmp;
1463 if (f >= 0) {
1464 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));
1465 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));
1466 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1467 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));
1468 #endif
1469 wtmp.ut_time = time(NULL);
1470 write(f, &wtmp, sizeof(wtmp));
1471 close(f);
1474 #endif
1475 free (utxp);
1477 endutxent();
1478 } /* end of rmut */
1479 #endif
1481 #if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43
1482 static void
1483 rmut(void)
1485 int f;
1486 int found = 0;
1487 struct utmp *u, *utmp;
1488 int nutmp;
1489 struct stat statbf;
1490 char *clean_tty = clean_ttyname(line);
1492 f = open(utmpf, O_RDWR);
1493 if (f >= 0) {
1494 fstat(f, &statbf);
1495 utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
1496 if (!utmp)
1497 syslog(LOG_ERR, "utmp malloc failed");
1498 if (statbf.st_size && utmp) {
1499 nutmp = read(f, utmp, (int)statbf.st_size);
1500 nutmp /= sizeof(struct utmp);
1502 for (u = utmp ; u < &utmp[nutmp] ; u++) {
1503 if (strncmp(u->ut_line,
1504 clean_tty,
1505 sizeof(u->ut_line)) ||
1506 u->ut_name[0]==0)
1507 continue;
1508 lseek(f, ((long)u)-((long)utmp), L_SET);
1509 strncpy(u->ut_name, "", sizeof(u->ut_name));
1510 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1511 strncpy(u->ut_host, "", sizeof(u->ut_host));
1512 #endif
1513 u->ut_time = time(NULL);
1514 write(f, u, sizeof(wtmp));
1515 found++;
1518 close(f);
1520 if (found) {
1521 f = open(wtmpf, O_WRONLY|O_APPEND);
1522 if (f >= 0) {
1523 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));
1524 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));
1525 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1526 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));
1527 #endif
1528 wtmp.ut_time = time(NULL);
1529 write(f, &wtmp, sizeof(wtmp));
1530 close(f);
1533 chmod(line, 0666);
1534 chown(line, 0, 0);
1535 line[strlen("/dev/")] = 'p';
1536 chmod(line, 0666);
1537 chown(line, 0, 0);
1538 } /* end of rmut */
1539 #endif /* CRAY */
1541 #if defined(__hpux) && !defined(HAVE_UTMPX_H)
1542 static void
1543 rmut (char *line)
1545 struct utmp utmp;
1546 struct utmp *utptr;
1547 int fd; /* for /etc/wtmp */
1549 utmp.ut_type = USER_PROCESS;
1550 strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line));
1551 setutent();
1552 utptr = getutline(&utmp);
1553 /* write it out only if it exists */
1554 if (utptr) {
1555 utptr->ut_type = DEAD_PROCESS;
1556 utptr->ut_time = time(NULL);
1557 pututline(utptr);
1558 /* set wtmp entry if wtmp file exists */
1559 if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
1560 write(fd, utptr, sizeof(utmp));
1561 close(fd);
1564 endutent();
1566 chmod(line, 0666);
1567 chown(line, 0, 0);
1568 line[14] = line[13];
1569 line[13] = line[12];
1570 line[8] = 'm';
1571 line[9] = '/';
1572 line[10] = 'p';
1573 line[11] = 't';
1574 line[12] = 'y';
1575 chmod(line, 0666);
1576 chown(line, 0, 0);
1578 #endif
1581 * cleanup()
1583 * This is the routine to call when we are all through, to
1584 * clean up anything that needs to be cleaned up.
1587 #ifdef PARENT_DOES_UTMP
1589 void
1590 cleanup(int sig)
1592 #ifdef _CRAY
1593 static int incleanup = 0;
1594 int t;
1595 int child_status; /* status of child process as returned by waitpid */
1596 int flags = WNOHANG|WUNTRACED;
1599 * 1: Pick up the zombie, if we are being called
1600 * as the signal handler.
1601 * 2: If we are a nested cleanup(), return.
1602 * 3: Try to clean up TMPDIR.
1603 * 4: Fill in utmp with shutdown of process.
1604 * 5: Close down the network and pty connections.
1605 * 6: Finish up the TMPDIR cleanup, if needed.
1607 if (sig == SIGCHLD) {
1608 while (waitpid(-1, &child_status, flags) > 0)
1609 ; /* VOID */
1610 /* Check if the child process was stopped
1611 * rather than exited. We want cleanup only if
1612 * the child has died.
1614 if (WIFSTOPPED(child_status)) {
1615 return;
1618 t = sigblock(sigmask(SIGCHLD));
1619 if (incleanup) {
1620 sigsetmask(t);
1621 return;
1623 incleanup = 1;
1624 sigsetmask(t);
1626 t = cleantmp(&wtmp);
1627 setutent(); /* just to make sure */
1628 #endif /* CRAY */
1629 rmut(line);
1630 close(ourpty);
1631 shutdown(net, 2);
1632 #ifdef _CRAY
1633 if (t == 0)
1634 cleantmp(&wtmp);
1635 #endif /* CRAY */
1636 exit(1);
1639 #else /* PARENT_DOES_UTMP */
1641 void
1642 cleanup(int sig)
1644 #if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)
1645 rmut();
1646 #ifdef HAVE_VHANGUP
1647 #ifndef __sgi
1648 vhangup(); /* XXX */
1649 #endif
1650 #endif
1651 #else
1652 char *p;
1654 p = line + sizeof("/dev/") - 1;
1655 if (logout(p))
1656 logwtmp(p, "", "");
1657 chmod(line, 0666);
1658 chown(line, 0, 0);
1659 *p = 'p';
1660 chmod(line, 0666);
1661 chown(line, 0, 0);
1662 #endif
1663 shutdown(net, 2);
1664 exit(1);
1667 #endif /* PARENT_DOES_UTMP */
1669 #ifdef PARENT_DOES_UTMP
1671 * _utmp_sig_rcv
1672 * utmp_sig_init
1673 * utmp_sig_wait
1674 * These three functions are used to coordinate the handling of
1675 * the utmp file between the server and the soon-to-be-login shell.
1676 * The server actually creates the utmp structure, the child calls
1677 * utmp_sig_wait(), until the server calls utmp_sig_notify() and
1678 * signals the future-login shell to proceed.
1680 static int caught=0; /* NZ when signal intercepted */
1681 static void (*func)(); /* address of previous handler */
1683 void
1684 _utmp_sig_rcv(sig)
1685 int sig;
1687 caught = 1;
1688 signal(SIGUSR1, func);
1691 void
1692 utmp_sig_init()
1695 * register signal handler for UTMP creation
1697 if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1698 fatalperror(net, "telnetd/signal");
1701 void
1702 utmp_sig_reset()
1704 signal(SIGUSR1, func); /* reset handler to default */
1707 # ifdef __hpux
1708 # define sigoff() /* do nothing */
1709 # define sigon() /* do nothing */
1710 # endif
1712 void
1713 utmp_sig_wait()
1716 * Wait for parent to write our utmp entry.
1718 sigoff();
1719 while (caught == 0) {
1720 pause(); /* wait until we get a signal (sigon) */
1721 sigoff(); /* turn off signals while we check caught */
1723 sigon(); /* turn on signals again */
1726 void
1727 utmp_sig_notify(pid)
1729 kill(pid, SIGUSR1);
1732 #ifdef _CRAY
1733 static int gotsigjob = 0;
1735 /*ARGSUSED*/
1736 void
1737 sigjob(sig)
1738 int sig;
1740 int jid;
1741 struct jobtemp *jp;
1743 while ((jid = waitjob(NULL)) != -1) {
1744 if (jid == 0) {
1745 return;
1747 gotsigjob++;
1748 jobend(jid, NULL, NULL);
1753 * jid_getutid:
1754 * called by jobend() before calling cleantmp()
1755 * to find the correct $TMPDIR to cleanup.
1758 struct utmp *
1759 jid_getutid(jid)
1760 int jid;
1762 struct utmp *cur = NULL;
1764 setutent(); /* just to make sure */
1765 while (cur = getutent()) {
1766 if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
1767 return(cur);
1771 return(0);
1775 * Clean up the TMPDIR that login created.
1776 * The first time this is called we pick up the info
1777 * from the utmp. If the job has already gone away,
1778 * then we'll clean up and be done. If not, then
1779 * when this is called the second time it will wait
1780 * for the signal that the job is done.
1783 cleantmp(wtp)
1784 struct utmp *wtp;
1786 struct utmp *utp;
1787 static int first = 1;
1788 int mask, omask, ret;
1789 extern struct utmp *getutid (const struct utmp *_Id);
1792 mask = sigmask(WJSIGNAL);
1794 if (first == 0) {
1795 omask = sigblock(mask);
1796 while (gotsigjob == 0)
1797 sigpause(omask);
1798 return(1);
1800 first = 0;
1801 setutent(); /* just to make sure */
1803 utp = getutid(wtp);
1804 if (utp == 0) {
1805 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1806 return(-1);
1809 * Nothing to clean up if the user shell was never started.
1811 if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
1812 return(1);
1815 * Block the WJSIGNAL while we are in jobend().
1817 omask = sigblock(mask);
1818 ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
1819 sigsetmask(omask);
1820 return(ret);
1824 jobend(jid, path, user)
1825 int jid;
1826 char *path;
1827 char *user;
1829 static int saved_jid = 0;
1830 static int pty_saved_jid = 0;
1831 static char saved_path[sizeof(wtmp.ut_tpath)+1];
1832 static char saved_user[sizeof(wtmp.ut_user)+1];
1835 * this little piece of code comes into play
1836 * only when ptyreconnect is used to reconnect
1837 * to an previous session.
1839 * this is the only time when the
1840 * "saved_jid != jid" code is executed.
1843 if ( saved_jid && saved_jid != jid ) {
1844 if (!path) { /* called from signal handler */
1845 pty_saved_jid = jid;
1846 } else {
1847 pty_saved_jid = saved_jid;
1851 if (path) {
1852 strlcpy(saved_path, path, sizeof(saved_path));
1853 strlcpy(saved_user, user, sizeof(saved_user));
1855 if (saved_jid == 0) {
1856 saved_jid = jid;
1857 return(0);
1860 /* if the jid has changed, get the correct entry from the utmp file */
1862 if ( saved_jid != jid ) {
1863 struct utmp *utp = NULL;
1864 struct utmp *jid_getutid();
1866 utp = jid_getutid(pty_saved_jid);
1868 if (utp == 0) {
1869 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1870 return(-1);
1873 cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
1874 return(1);
1877 cleantmpdir(jid, saved_path, saved_user);
1878 return(1);
1882 * Fork a child process to clean up the TMPDIR
1884 cleantmpdir(jid, tpath, user)
1885 int jid;
1886 char *tpath;
1887 char *user;
1889 switch(fork()) {
1890 case -1:
1891 syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
1892 tpath);
1893 break;
1894 case 0:
1895 execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, NULL);
1896 syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1897 tpath, CLEANTMPCMD);
1898 exit(1);
1899 default:
1901 * Forget about child. We will exit, and
1902 * /etc/init will pick it up.
1904 break;
1907 #endif /* CRAY */
1908 #endif /* defined(PARENT_DOES_UTMP) */