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
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
35 static const char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95";
39 #include "pathnames.h"
41 #if defined(AUTHENTICATION)
42 #include <libtelnet/auth.h>
45 extern char *altlogin;
46 int cleanopen(char *line);
49 #if defined(CRAY) || defined(__hpux)
50 # define PARENT_DOES_UTMP
53 int utmp_len = MAXHOSTNAMELEN;
65 # ifndef PARENT_DOES_UTMP
67 char wtmpf[] = _PATH_WTMP;
69 char wtmpf[] = "/usr/adm/wtmp";
72 char utmpf[] = _PATH_UTMP;
74 char utmpf[] = "/etc/utmp";
76 # else /* PARENT_DOES_UTMP */
77 char wtmpf[] = "/etc/wtmp";
78 # endif /* PARENT_DOES_UTMP */
85 # if (UNICOS_LVL == '7.0') || (UNICOS_LVL == '7.1')
91 #include <sys/secstat.h>
93 extern struct sysv sysv;
94 # endif /* UNICOS7x */
100 #include <sys/stropts.h>
103 #define SCPYN(a, b) (void) strncpy(a, b, sizeof(a))
104 #define SCMPN(a, b) strncmp(a, b, sizeof(a))
107 #include <sys/stream.h>
110 #include <sys/resource.h>
111 #include <sys/proc.h>
131 #if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC)
132 # define EXTPROC 0400
143 # define cfsetospeed(tp, val) (tp)->sg.sg_ospeed = (val)
144 # define cfsetispeed(tp, val) (tp)->sg.sg_ispeed = (val)
145 # define cfgetospeed(tp) (tp)->sg.sg_ospeed
146 # define cfgetispeed(tp) (tp)->sg.sg_ispeed
147 #else /* USE_TERMIO */
149 # define termios termio
153 # define TCSANOW TCSETS
154 # define TCSADRAIN TCSETSW
155 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
158 # define TCSANOW TCSETA
159 # define TCSADRAIN TCSETAW
160 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
162 # define TCSANOW TIOCSETA
163 # define TCSADRAIN TIOCSETAW
164 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
167 # define tcsetattr(f, a, t) ioctl(f, a, t)
168 # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
169 (tp)->c_cflag |= (val)
170 # define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
172 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
173 (tp)->c_cflag |= ((val)<<IBSHIFT)
174 # define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
176 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
177 (tp)->c_cflag |= (val)
178 # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
180 # endif /* TCSANOW */
181 struct termios termbuf, termbuf2; /* pty control structure */
185 #endif /* USE_TERMIO */
192 * These three routines are used to get and set the "termbuf" structure
193 * to and from the kernel. init_termbuf() gets the current settings.
194 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
195 * set_termbuf() writes the structure into the kernel.
202 (void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg);
203 (void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc);
204 (void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc);
206 (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
210 (void) tcgetattr(ttyfd, &termbuf);
212 (void) tcgetattr(pty, &termbuf);
218 #if defined(LINEMODE) && defined(TIOCPKT_IOCTL)
220 copy_termbuf(cp, len)
224 if (len > sizeof(termbuf))
225 len = sizeof(termbuf);
226 memmove((char *)&termbuf, cp, len);
229 #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
235 * Only make the necessary changes.
238 if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg,
240 (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg);
241 if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc,
243 (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
244 if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
245 sizeof(termbuf.ltc)))
246 (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
247 if (termbuf.lflags != termbuf2.lflags)
248 (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
249 #else /* USE_TERMIO */
250 if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
252 (void) tcsetattr(ttyfd, TCSANOW, &termbuf);
254 (void) tcsetattr(pty, TCSANOW, &termbuf);
256 # if defined(CRAY2) && defined(UNICOS5)
259 #endif /* USE_TERMIO */
264 * spcset(func, valp, valpp)
266 * This function takes various special characters (func), and
267 * sets *valp to the current value of that character, and
268 * *valpp to point to where in the "termbuf" structure that
271 * It returns the SLC_ level of support for this function.
276 spcset(func, valp, valpp)
283 *valp = termbuf.tc.t_eofc;
284 *valpp = (cc_t *)&termbuf.tc.t_eofc;
285 return(SLC_VARIABLE);
287 *valp = termbuf.sg.sg_erase;
288 *valpp = (cc_t *)&termbuf.sg.sg_erase;
289 return(SLC_VARIABLE);
291 *valp = termbuf.sg.sg_kill;
292 *valpp = (cc_t *)&termbuf.sg.sg_kill;
293 return(SLC_VARIABLE);
295 *valp = termbuf.tc.t_intrc;
296 *valpp = (cc_t *)&termbuf.tc.t_intrc;
297 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
299 *valp = termbuf.tc.t_quitc;
300 *valpp = (cc_t *)&termbuf.tc.t_quitc;
301 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
303 *valp = termbuf.tc.t_startc;
304 *valpp = (cc_t *)&termbuf.tc.t_startc;
305 return(SLC_VARIABLE);
307 *valp = termbuf.tc.t_stopc;
308 *valpp = (cc_t *)&termbuf.tc.t_stopc;
309 return(SLC_VARIABLE);
311 *valp = termbuf.ltc.t_flushc;
312 *valpp = (cc_t *)&termbuf.ltc.t_flushc;
313 return(SLC_VARIABLE);
315 *valp = termbuf.ltc.t_suspc;
316 *valpp = (cc_t *)&termbuf.ltc.t_suspc;
317 return(SLC_VARIABLE);
319 *valp = termbuf.ltc.t_werasc;
320 *valpp = (cc_t *)&termbuf.ltc.t_werasc;
321 return(SLC_VARIABLE);
323 *valp = termbuf.ltc.t_rprntc;
324 *valpp = (cc_t *)&termbuf.ltc.t_rprntc;
325 return(SLC_VARIABLE);
327 *valp = termbuf.ltc.t_lnextc;
328 *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
329 return(SLC_VARIABLE);
331 *valp = termbuf.tc.t_brkc;
332 *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
333 return(SLC_VARIABLE);
344 return(SLC_NOSUPPORT);
348 #else /* USE_TERMIO */
351 spcset(func, valp, valpp)
357 #define setval(a, b) *valp = termbuf.c_cc[a]; \
358 *valpp = &termbuf.c_cc[a]; \
360 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
364 setval(VEOF, SLC_VARIABLE);
366 setval(VERASE, SLC_VARIABLE);
368 setval(VKILL, SLC_VARIABLE);
370 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
372 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
375 setval(VSTART, SLC_VARIABLE);
381 setval(VSTOP, SLC_VARIABLE);
387 setval(VWERASE, SLC_VARIABLE);
393 setval(VREPRINT, SLC_VARIABLE);
399 setval(VLNEXT, SLC_VARIABLE);
404 #if !defined(VDISCARD) && defined(VFLUSHO)
405 # define VDISCARD VFLUSHO
408 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
414 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
420 setval(VEOL, SLC_VARIABLE);
424 setval(VEOL2, SLC_VARIABLE);
428 setval(VSTATUS, SLC_VARIABLE);
441 return(SLC_NOSUPPORT);
444 #endif /* USE_TERMIO */
450 * Return the number of pty's configured into the system.
458 if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
461 #endif /* _SC_CRAY_NPTY */
470 * Allocate a pty. As a side effect, the external character
471 * array "line" contains the name of the slave side.
473 * Returns the file descriptor of the opened pty.
476 char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
478 static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
482 char *myline = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
494 p = open("/dev/ptmx", 2);
498 strcpy(line, ptsname(p));
502 #else /* ! STREAMSPTY */
504 register char *cp, *p1, *p2;
506 #if defined(sun) && defined(TIOCGPGRP) && BSD < 199207
511 (void) sprintf(line, "/dev/ptyXX");
515 (void) sprintf(line, "/dev/ptym/ptyXX");
520 for (cp = "pqrsPQRS"; *cp; cp++) {
526 * This stat() check is just to keep us from
527 * looping through all 256 combinations if there
528 * aren't that many ptys available.
530 if (stat(line, &stb) < 0)
532 for (i = 0; i < 32; i++) {
533 *p2 = "0123456789abcdefghijklmnopqrstuv"[i];
539 for (p1 = &line[8]; *p1; p1++)
545 #if defined(sun) && defined(TIOCGPGRP) && BSD < 199207
546 if (ioctl(p, TIOCGPGRP, &dummy) == 0
552 #endif /* defined(sun) && defined(TIOCGPGRP) && BSD < 199207 */
558 extern lowpty, highpty;
561 for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {
562 (void) sprintf(myline, "/dev/pty/%03d", *ptynum);
566 (void) sprintf(line, "/dev/ttyp%03d", *ptynum);
568 * Here are some shenanigans to make sure that there
569 * are no listeners lurking on the line.
571 if(stat(line, &sb) < 0) {
575 if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
584 * Now it should be safe...check for accessability.
586 if (access(line, 6) == 0)
589 /* no tty side to pty so skip it */
594 #endif /* STREAMSPTY */
601 * tty_flowmode() Find out if flow control is enabled or disabled.
602 * tty_linemode() Find out if linemode (external processing) is enabled.
603 * tty_setlinemod(on) Turn on/off linemode.
604 * tty_isecho() Find out if echoing is turned on.
605 * tty_setecho(on) Enable/disable character echoing.
606 * tty_israw() Find out if terminal is in RAW mode.
607 * tty_binaryin(on) Turn on/off BINARY on input.
608 * tty_binaryout(on) Turn on/off BINARY on output.
609 * tty_isediting() Find out if line editing is enabled.
610 * tty_istrapsig() Find out if signal trapping is enabled.
611 * tty_setedit(on) Turn on/off line editing.
612 * tty_setsig(on) Turn on/off signal trapping.
613 * tty_issofttab() Find out if tab expansion is enabled.
614 * tty_setsofttab(on) Turn on/off soft tab expansion.
615 * tty_islitecho() Find out if typed control chars are echoed literally
616 * tty_setlitecho() Turn on/off literal echo of control chars
617 * tty_tspeed(val) Set transmit speed to val.
618 * tty_rspeed(val) Set receive speed to val.
622 static int linestate;
630 return(termbuf.state & TS_EXTPROC);
632 return(termbuf.c_lflag & EXTPROC);
649 (void) ioctl(pty, TIOCEXT, (char *)&on);
656 termbuf.c_lflag |= EXTPROC;
658 termbuf.c_lflag &= ~EXTPROC;
662 #endif /* LINEMODE */
668 return (termbuf.sg.sg_flags & ECHO);
670 return (termbuf.c_lflag & ECHO);
678 return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
680 return((termbuf.c_iflag & IXON) ? 1 : 0);
689 return((termbuf.lflags & DECCTQ) ? 0 : 1);
694 return((termbuf.c_iflag & IXANY) ? 1 : 0);
704 termbuf.sg.sg_flags |= ECHO|CRMOD;
706 termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
709 termbuf.c_lflag |= ECHO;
711 termbuf.c_lflag &= ~ECHO;
719 return(termbuf.sg.sg_flags & RAW);
721 return(!(termbuf.c_lflag & ICANON));
725 #if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
731 termbuf.sg.sg_flags |= RAW;
733 termbuf.sg.sg_flags &= ~RAW;
736 termbuf.c_lflag &= ~ICANON;
738 termbuf.c_lflag |= ICANON;
749 termbuf.lflags |= LPASS8;
751 termbuf.lflags &= ~LPASS8;
754 termbuf.c_iflag &= ~ISTRIP;
756 termbuf.c_iflag |= ISTRIP;
767 termbuf.lflags |= LLITOUT;
769 termbuf.lflags &= ~LLITOUT;
772 termbuf.c_cflag &= ~(CSIZE|PARENB);
773 termbuf.c_cflag |= CS8;
774 termbuf.c_oflag &= ~OPOST;
776 termbuf.c_cflag &= ~CSIZE;
777 termbuf.c_cflag |= CS7|PARENB;
778 termbuf.c_oflag |= OPOST;
787 return(termbuf.lflags & LPASS8);
789 return(!(termbuf.c_iflag & ISTRIP));
797 return(termbuf.lflags & LLITOUT);
799 return(!(termbuf.c_oflag&OPOST));
808 return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
810 return(termbuf.c_lflag & ICANON);
818 return(!(termbuf.sg.sg_flags&RAW));
820 return(termbuf.c_lflag & ISIG);
830 termbuf.sg.sg_flags &= ~CBREAK;
832 termbuf.sg.sg_flags |= CBREAK;
835 termbuf.c_lflag |= ICANON;
837 termbuf.c_lflag &= ~ICANON;
850 termbuf.c_lflag |= ISIG;
852 termbuf.c_lflag &= ~ISIG;
855 #endif /* LINEMODE */
861 return (termbuf.sg.sg_flags & XTABS);
864 return (termbuf.c_oflag & OXTABS);
867 return ((termbuf.c_oflag & TABDLY) == TAB3);
878 termbuf.sg.sg_flags |= XTABS;
880 termbuf.sg.sg_flags &= ~XTABS;
884 termbuf.c_oflag |= OXTABS;
887 termbuf.c_oflag &= ~TABDLY;
888 termbuf.c_oflag |= TAB3;
892 termbuf.c_oflag &= ~OXTABS;
895 termbuf.c_oflag &= ~TABDLY;
896 termbuf.c_oflag |= TAB0;
906 return (!(termbuf.lflags & LCTLECH));
909 return (!(termbuf.c_lflag & ECHOCTL));
912 return (!(termbuf.c_lflag & TCTLECH));
914 # if !defined(ECHOCTL) && !defined(TCTLECH)
915 return (0); /* assumes ctl chars are echoed '^x' */
926 termbuf.lflags &= ~LCTLECH;
928 termbuf.lflags |= LCTLECH;
932 termbuf.c_lflag &= ~ECHOCTL;
934 termbuf.c_lflag |= ECHOCTL;
938 termbuf.c_lflag &= ~TCTLECH;
940 termbuf.c_lflag |= TCTLECH;
949 return (termbuf.sg.sg_flags & CRMOD);
951 return (termbuf.c_iflag & ICRNL);
956 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
965 * A table of available terminal speeds
971 { 0, B0 }, { 50, B50 }, { 75, B75 },
972 { 110, B110 }, { 134, B134 }, { 150, B150 },
973 { 200, B200 }, { 300, B300 }, { 600, B600 },
974 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
1003 #endif /* DECODE_BUAD */
1010 register struct termspeeds *tp;
1012 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
1014 if (tp->speed == -1) /* back up to last valid value */
1016 cfsetospeed(&termbuf, tp->value);
1017 #else /* DECODE_BUAD */
1018 cfsetospeed(&termbuf, val);
1019 #endif /* DECODE_BUAD */
1027 register struct termspeeds *tp;
1029 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
1031 if (tp->speed == -1) /* back up to last valid value */
1033 cfsetispeed(&termbuf, tp->value);
1034 #else /* DECODE_BAUD */
1035 cfsetispeed(&termbuf, val);
1036 #endif /* DECODE_BAUD */
1039 #if defined(CRAY2) && defined(UNICOS5)
1043 return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) &&
1044 !(termbuf.c_oflag & ONLRET));
1048 #ifdef PARENT_DOES_UTMP
1050 extern struct utmp wtmp;
1051 extern char wtmpf[];
1052 # else /* NEWINIT */
1062 # endif /* NEWINIT */
1063 #endif /* PARENT_DOES_UTMP */
1066 # ifdef PARENT_DOES_UTMP
1067 extern void utmp_sig_init P((void));
1068 extern void utmp_sig_reset P((void));
1069 extern void utmp_sig_wait P((void));
1070 extern void utmp_sig_notify P((int));
1071 # endif /* PARENT_DOES_UTMP */
1077 * Open the slave side of the pty, and do any initialization
1078 * that is necessary. The return value is a file descriptor
1079 * for the slave side.
1084 register int t = -1;
1087 #if !defined(CRAY) || !defined(NEWINIT)
1093 extern int def_row, def_col;
1095 extern int def_tspeed, def_rspeed;
1097 * Opening the slave side may cause initilization of the
1098 * kernel tty structure. We need remember the state of
1099 * if linemode was turned on
1100 * terminal window size
1103 * so that we can re-set them if we need to.
1106 waslm = tty_linemode();
1108 erase = termbuf.c_cc[VERASE];
1111 * Make sure that we don't have a controlling tty, and
1112 * that we are the session (process group) leader.
1115 t = open(_PATH_TTY, O_RDWR);
1117 (void) ioctl(t, TIOCNOTTY, (char *)0);
1123 # ifdef PARENT_DOES_UTMP
1125 * Wait for our parent to get the utmp stuff to get done.
1130 t = cleanopen(line);
1132 fatalperror(net, line);
1138 if (ioctl(t, I_PUSH, "ptem") < 0)
1139 fatal(net, "I_PUSH ptem");
1140 if (ioctl(t, I_PUSH, "ldterm") < 0)
1141 fatal(net, "I_PUSH ldterm");
1142 if (ioctl(t, I_PUSH, "ttcompat") < 0)
1143 fatal(net, "I_PUSH ttcompat");
1144 if (ioctl(pty, I_PUSH, "pckt") < 0)
1145 fatal(net, "I_PUSH pckt");
1149 * set up the tty modes as we like them to be.
1153 if (def_row || def_col) {
1154 memset((char *)&ws, 0, sizeof(ws));
1155 ws.ws_col = def_col;
1156 ws.ws_row = def_row;
1157 (void)ioctl(t, TIOCSWINSZ, (char *)&ws);
1162 * Settings for sgtty based systems
1165 termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
1166 # endif /* USE_TERMIO */
1169 * Settings for UNICOS (and HPUX)
1171 # if defined(CRAY) || defined(__hpux)
1172 termbuf.c_oflag = OPOST|ONLCR|TAB3;
1173 termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
1174 termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
1175 termbuf.c_cflag = EXTB|HUPCL|CS8;
1179 * Settings for all other termios/termio based
1180 * systems, other than 4.4BSD. In 4.4BSD the
1181 * kernel does the initial terminal setup.
1183 # if defined(USE_TERMIO) && !(defined(CRAY) || defined(__hpux)) && (BSD <= 43)
1187 termbuf.c_lflag |= ECHO;
1188 termbuf.c_oflag |= ONLCR|OXTABS;
1189 termbuf.c_iflag |= ICRNL;
1190 termbuf.c_iflag &= ~IXOFF;
1191 # endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */
1192 tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
1193 tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
1195 termbuf.c_cc[VERASE] = erase;
1199 # endif /* LINEMODE */
1202 * Set the tty modes, and make this our controlling tty.
1205 if (login_tty(t) == -1)
1206 fatalperror(net, "login_tty");
1207 #endif /* !defined(CRAY) || !defined(NEWINIT) */
1210 #if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1212 * Leave the pty open so that we can write out the rlogin
1213 * protocol for /bin/login, if the authentication works.
1223 #if !defined(CRAY) || !defined(NEWINIT)
1228 * Open the specified slave side of the pty,
1229 * making sure that we have a clean tty.
1237 struct secstat secbuf;
1238 #endif /* UNICOS7x */
1242 * Make sure that other people can't open the
1243 * slave side of the connection.
1245 (void) chown(line, 0, 0);
1246 (void) chmod(line, 0600);
1249 # if !defined(CRAY) && (BSD > 43)
1250 (void) revoke(line);
1254 if (secstat(line, &secbuf) < 0)
1256 if (setulvl(secbuf.st_slevel) < 0)
1258 if (setucmp(secbuf.st_compart) < 0)
1261 #endif /* UNICOS7x */
1263 t = open(line, O_RDWR|O_NOCTTY);
1267 if (setulvl(sysv.sy_minlvl) < 0)
1272 #endif /* UNICOS7x */
1278 * Hangup anybody else using this ttyp, then reopen it for
1281 # if !(defined(CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
1282 (void) signal(SIGHUP, SIG_IGN);
1284 (void) signal(SIGHUP, SIG_DFL);
1285 t = open(line, O_RDWR|O_NOCTTY);
1289 # if defined(CRAY) && defined(TCVHUP)
1292 (void) signal(SIGHUP, SIG_IGN);
1293 (void) ioctl(t, TCVHUP, (char *)0);
1294 (void) signal(SIGHUP, SIG_DFL);
1298 if (secstat(line, &secbuf) < 0)
1300 if (setulvl(secbuf.st_slevel) < 0)
1302 if (setucmp(secbuf.st_compart) < 0)
1305 #endif /* UNICOS7x */
1307 i = open(line, O_RDWR);
1311 if (setulvl(sysv.sy_minlvl) < 0)
1316 #endif /* UNICOS7x */
1323 # endif /* defined(CRAY) && defined(TCVHUP) */
1326 #endif /* !defined(CRAY) || !defined(NEWINIT) */
1337 * The setsid() may have failed because we
1338 * already have a pgrp == pid. Zero out
1339 * our pgrp and try again...
1341 if ((setpgrp(0, 0) < 0) || (setsid() < 0))
1343 fatalperror(net, "setsid()");
1346 if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
1347 fatalperror(net, "ioctl(sctty)");
1350 * Close the hard fd to /dev/ttypXXX, and re-open through
1351 * the indirect /dev/tty interface.
1354 if ((t = open("/dev/tty", O_RDWR)) < 0)
1355 fatalperror(net, "open(/dev/tty)");
1359 * We get our controlling tty assigned as a side-effect
1360 * of opening up a tty device. But on BSD based systems,
1361 * this only happens if our process group is zero. The
1362 * setsid() call above may have set our pgrp, so clear
1363 * it out before opening the tty...
1366 (void) setpgrp(0, 0);
1370 close(open(line, O_RDWR));
1382 #endif /* BSD <= 43 */
1385 char *gen_id = "fe";
1391 * Given a hostname, do whatever
1392 * is necessary to startup the login process on the slave side of the pty.
1397 startslave(host, autologin, autoname)
1406 struct init_request request;
1409 #endif /* NEWINIT */
1411 #if defined(AUTHENTICATION)
1412 if (!autoname || !autoname[0])
1415 if (autologin < auth_level) {
1416 fatal(net, "Authorization failed");
1422 # ifdef PARENT_DOES_UTMP
1424 # endif /* PARENT_DOES_UTMP */
1426 if ((i = fork()) < 0)
1427 fatalperror(net, "fork");
1429 # ifdef PARENT_DOES_UTMP
1431 * Cray parent will create utmp entry for child and send
1432 * signal to child to tell when done. Child waits for signal
1433 * before doing anything important.
1435 register int pid = i;
1436 void sigjob P((int));
1439 utmp_sig_reset(); /* reset handler to default */
1441 * Create utmp entry for child
1443 (void) time(&wtmp.ut_time);
1444 wtmp.ut_type = LOGIN_PROCESS;
1446 SCPYN(wtmp.ut_user, "LOGIN");
1447 SCPYN(wtmp.ut_host, host);
1448 SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1);
1450 SCPYN(wtmp.ut_id, wtmp.ut_line+3);
1452 SCPYN(wtmp.ut_id, wtmp.ut_line+7);
1456 if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
1457 (void) write(i, (char *)&wtmp, sizeof(struct utmp));
1461 (void) signal(WJSIGNAL, sigjob);
1463 utmp_sig_notify(pid);
1464 # endif /* PARENT_DOES_UTMP */
1466 getptyslave(autologin);
1467 start_login(host, autologin, autoname);
1473 * Init will start up login process if we ask nicely. We only wait
1474 * for it to start up and begin normal telnet operation.
1476 if ((i = open(INIT_FIFO, O_WRONLY)) < 0) {
1478 (void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO);
1479 fatalperror(net, tbuf);
1481 memset((char *)&request, 0, sizeof(request));
1482 request.magic = INIT_MAGIC;
1483 SCPYN(request.gen_id, gen_id);
1484 SCPYN(request.tty_id, &line[8]);
1485 SCPYN(request.host, host);
1486 SCPYN(request.term_type, terminaltype ? terminaltype : "network");
1487 #if !defined(UNICOS5)
1488 request.signal = SIGCLD;
1489 request.pid = getpid();
1493 * Are we working as the bftp daemon?
1496 SCPYN(request.exec_name, BFTPPATH);
1498 #endif /* BFTPDAEMON */
1499 if (write(i, (char *)&request, sizeof(request)) < 0) {
1501 (void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO);
1502 fatalperror(net, tbuf);
1505 (void) signal(SIGALRM, nologinproc);
1506 for (i = 0; ; i++) {
1509 n = read(pty, ptyip, BUFSIZ);
1510 if (i == 3 || n >= 0 || !gotalarm)
1513 sprintf(tbuf, "telnetd: waiting for /etc/init to start login process on %s\r\n", line);
1514 (void) write(net, tbuf, strlen(tbuf));
1516 if (n < 0 && gotalarm)
1517 fatal(net, "/etc/init didn't start login process");
1520 (void) signal(SIGALRM, SIG_DFL);
1523 #endif /* NEWINIT */
1527 extern char **environ;
1532 extern char *getenv();
1536 if ((*envp = getenv("TZ")))
1538 #if defined(CRAY) || defined(__hpux)
1540 *envp++ = "TZ=GMT0";
1551 * Assuming that we are now running as a child processes, this
1552 * function will turn us into the login process.
1556 start_login(host, autologin, name)
1561 register char **argv;
1562 char **addarg(), *user;
1563 extern char *getenv();
1565 register int pid = getpid();
1575 * Create utmp entry for child
1578 memset(&utmpx, 0, sizeof(utmpx));
1579 SCPYN(utmpx.ut_user, ".telnet");
1580 SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1);
1582 utmpx.ut_id[0] = 't';
1583 utmpx.ut_id[1] = 'n';
1584 utmpx.ut_id[2] = SC_WILDC;
1585 utmpx.ut_id[3] = SC_WILDC;
1586 utmpx.ut_type = LOGIN_PROCESS;
1587 (void) time(&utmpx.ut_tv.tv_sec);
1588 if (makeutx(&utmpx) == NULL)
1589 fatal(net, "makeutx failed");
1595 * -h : pass on name of host.
1596 * WARNING: -h is accepted by login if and only if
1598 * -p : don't clobber the environment (so terminal type stays set).
1600 * -f : force this login, he has already been authenticated
1602 argv = addarg(0, "login");
1604 #if !defined(NO_LOGIN_H)
1606 # if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1608 * Don't add the "-h host" option if we are going
1609 * to be adding the "-r host" option down below...
1611 if ((auth_level < 0) || (autologin != AUTH_VALID))
1614 argv = addarg(argv, "-h");
1615 argv = addarg(argv, host);
1618 * SVR4 version of -h takes TERM= as second arg, or -
1620 term = getenv("TERM");
1621 if (term == NULL || term[0] == 0) {
1624 strcpy(termbuf, "TERM=");
1625 strncat(termbuf, term, sizeof(termbuf) - 6);
1628 argv = addarg(argv, term);
1632 #if !defined(NO_LOGIN_P)
1633 argv = addarg(argv, "-p");
1637 * Set the environment variable "LINEMODE" to either
1638 * "real" or "kludge" if we are operating in either
1639 * real or kludge linemode.
1641 if (lmodetype == REAL_LINEMODE)
1642 setenv("LINEMODE", "real", 1);
1643 # ifdef KLUDGELINEMODE
1644 else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK)
1645 setenv("LINEMODE", "kludge", 1);
1650 * Are we working as the bftp daemon? If so, then ask login
1651 * to start bftp instead of shell.
1654 argv = addarg(argv, "-e");
1655 argv = addarg(argv, BFTPPATH);
1658 #if defined (SecurID)
1660 * don't worry about the -f that might get sent.
1661 * A -s is supposed to override it anyhow.
1663 if (require_SecurID)
1664 argv = addarg(argv, "-s");
1666 #if defined (AUTHENTICATION)
1667 if (auth_level >= 0 && autologin == AUTH_VALID) {
1668 # if !defined(NO_LOGIN_F)
1669 argv = addarg(argv, "-f");
1670 argv = addarg(argv, "--");
1671 argv = addarg(argv, name);
1673 # if defined(LOGIN_R)
1675 * We don't have support for "login -f", but we
1676 * can fool /bin/login into thinking that we are
1677 * rlogind, and allow us to log in without a
1678 * password. The rlogin protocol expects
1679 * local-user\0remote-user\0term/speed\0
1685 int isecho, israw, xpty, len;
1686 extern int def_rspeed;
1689 * Tell login that we are coming from "localhost".
1690 * If we passed in the real host name, then the
1691 * user would have to allow .rhost access from
1692 * every machine that they want authenticated
1693 * access to work from, which sort of defeats
1694 * the purpose of an authenticated login...
1695 * So, we tell login that the session is coming
1696 * from "localhost", and the user will only have
1697 * to have "localhost" in their .rhost file.
1699 # define LOGIN_HOST "localhost"
1701 argv = addarg(argv, "-r");
1702 argv = addarg(argv, LOGIN_HOST);
1711 isecho = tty_isecho();
1712 israw = tty_israw();
1713 if (isecho || !israw) {
1714 tty_setecho(0); /* Turn off echo */
1715 tty_setraw(1); /* Turn on raw */
1718 len = strlen(name)+1;
1719 write(xpty, name, len);
1720 write(xpty, name, len);
1721 sprintf(speed, "%s/%d", (cp = getenv("TERM")) ? cp : "",
1722 (def_rspeed > 0) ? def_rspeed : 9600);
1723 len = strlen(speed)+1;
1724 write(xpty, speed, len);
1726 if (isecho || !israw) {
1728 tty_setecho(isecho);
1733 * Write a newline to ensure
1734 * that login will be able to
1737 write(xpty, "\n", 1);
1743 argv = addarg(argv, "--");
1744 argv = addarg(argv, name);
1749 if (getenv("USER")) {
1750 argv = addarg(argv, "--");
1751 argv = addarg(argv, getenv("USER"));
1752 #if defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
1754 register char **cpp;
1755 for (cpp = environ; *cpp; cpp++)
1756 argv = addarg(argv, *cpp);
1760 * Assume that login will set the USER variable
1761 * correctly. For SysV systems, this means that
1762 * USER will no longer be set, just LOGNAME by
1763 * login. (The problem is that if the auto-login
1764 * fails, and the user then specifies a different
1765 * account name, he can get logged in with both
1766 * LOGNAME and USER in his environment, but the
1767 * USER value will be wrong.
1775 argv = addarg(argv, ""); /* no login name */
1776 for (p = environ; *p; p++) {
1777 argv = addarg(argv, *p);
1780 #endif /* SOLARIS */
1781 #if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1787 if (altlogin == NULL) {
1788 altlogin = _PATH_LOGIN;
1790 execv(altlogin, argv);
1792 syslog(LOG_ERR, "%s: %m\n", altlogin);
1793 fatalperror(net, altlogin);
1799 register char **argv;
1802 register char **cpp;
1806 * 10 entries, a leading length, and a null
1808 argv = (char **)malloc(sizeof(*argv) * 12);
1811 *argv++ = (char *)10;
1814 for (cpp = argv; *cpp; cpp++)
1816 if (cpp == &argv[(int)argv[-1]]) {
1818 *argv = (char *)((int)(*argv) + 10);
1819 argv = (char **)realloc(argv, sizeof(*argv)*((int)(*argv) + 2));
1823 cpp = &argv[(int)argv[-1] - 10];
1829 #endif /* NEWINIT */
1834 * Remove a few things from the environment that
1835 * don't need to be there.
1840 register char **cpp, **cpp2;
1842 for (cpp2 = cpp = environ; *cpp; cpp++) {
1844 if (strncmp(*cpp, "LD_LIBRARY_PATH=", 16) &&
1845 strncmp(*cpp, "LD_PRELOAD=", 11) &&
1847 if (strncmp(*cpp, "LD_", 3) &&
1848 strncmp(*cpp, "_RLD_", 5) &&
1849 strncmp(*cpp, "LIBPATH=", 8) &&
1851 strncmp(*cpp, "IFS=", 4))
1860 * This is the routine to call when we are all through, to
1861 * clean up anything that needs to be cleaned up.
1868 #ifndef PARENT_DOES_UTMP
1869 # if (BSD > 43) || defined(convex)
1872 p = line + sizeof("/dev/") - 1;
1875 (void)chmod(line, 0666);
1876 (void)chown(line, 0, 0);
1878 (void)chmod(line, 0666);
1879 (void)chown(line, 0, 0);
1880 (void) shutdown(net, 2);
1886 vhangup(); /* XXX */
1887 (void) shutdown(net, 2);
1890 #else /* PARENT_DOES_UTMP */
1892 (void) shutdown(net, 2);
1894 # else /* NEWINIT */
1896 static int incleanup = 0;
1898 int child_status; /* status of child process as returned by waitpid */
1899 int flags = WNOHANG|WUNTRACED;
1902 * 1: Pick up the zombie, if we are being called
1903 * as the signal handler.
1904 * 2: If we are a nested cleanup(), return.
1905 * 3: Try to clean up TMPDIR.
1906 * 4: Fill in utmp with shutdown of process.
1907 * 5: Close down the network and pty connections.
1908 * 6: Finish up the TMPDIR cleanup, if needed.
1910 if (sig == SIGCHLD) {
1911 while (waitpid(-1, &child_status, flags) > 0)
1913 /* Check if the child process was stopped
1914 * rather than exited. We want cleanup only if
1915 * the child has died.
1917 if (WIFSTOPPED(child_status)) {
1921 t = sigblock(sigmask(SIGCHLD));
1931 * We need to set ourselves back to a null
1932 * label to clean up.
1935 setulvl(sysv.sy_minlvl);
1938 #endif /* UNICOS7x */
1940 t = cleantmp(&wtmp);
1941 setutent(); /* just to make sure */
1945 (void) shutdown(net, 2);
1951 # endif /* NEWINT */
1952 #endif /* PARENT_DOES_UTMP */
1955 #if defined(PARENT_DOES_UTMP) && !defined(NEWINIT)
1960 * These three functions are used to coordinate the handling of
1961 * the utmp file between the server and the soon-to-be-login shell.
1962 * The server actually creates the utmp structure, the child calls
1963 * utmp_sig_wait(), until the server calls utmp_sig_notify() and
1964 * signals the future-login shell to proceed.
1966 static int caught=0; /* NZ when signal intercepted */
1967 static void (*func)(); /* address of previous handler */
1974 (void) signal(SIGUSR1, func);
1981 * register signal handler for UTMP creation
1983 if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1984 fatalperror(net, "telnetd/signal");
1990 (void) signal(SIGUSR1, func); /* reset handler to default */
1994 # define sigoff() /* do nothing */
1995 # define sigon() /* do nothing */
2002 * Wait for parent to write our utmp entry.
2005 while (caught == 0) {
2006 pause(); /* wait until we get a signal (sigon) */
2007 sigoff(); /* turn off signals while we check caught */
2009 sigon(); /* turn on signals again */
2013 utmp_sig_notify(pid)
2019 static int gotsigjob = 0;
2027 register struct jobtemp *jp;
2029 while ((jid = waitjob(NULL)) != -1) {
2034 jobend(jid, NULL, NULL);
2040 * called by jobend() before calling cleantmp()
2041 * to find the correct $TMPDIR to cleanup.
2048 struct utmp *cur = NULL;
2050 setutent(); /* just to make sure */
2051 while (cur = getutent()) {
2052 if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
2061 * Clean up the TMPDIR that login created.
2062 * The first time this is called we pick up the info
2063 * from the utmp. If the job has already gone away,
2064 * then we'll clean up and be done. If not, then
2065 * when this is called the second time it will wait
2066 * for the signal that the job is done.
2070 register struct utmp *wtp;
2073 static int first = 1;
2074 register int mask, omask, ret;
2075 extern struct utmp *getutid P((const struct utmp *_Id));
2078 mask = sigmask(WJSIGNAL);
2081 omask = sigblock(mask);
2082 while (gotsigjob == 0)
2087 setutent(); /* just to make sure */
2091 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
2095 * Nothing to clean up if the user shell was never started.
2097 if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
2101 * Block the WJSIGNAL while we are in jobend().
2103 omask = sigblock(mask);
2104 ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
2110 jobend(jid, path, user)
2112 register char *path;
2113 register char *user;
2115 static int saved_jid = 0;
2116 static int pty_saved_jid = 0;
2117 static char saved_path[sizeof(wtmp.ut_tpath)+1];
2118 static char saved_user[sizeof(wtmp.ut_user)+1];
2121 * this little piece of code comes into play
2122 * only when ptyreconnect is used to reconnect
2123 * to an previous session.
2125 * this is the only time when the
2126 * "saved_jid != jid" code is executed.
2129 if ( saved_jid && saved_jid != jid ) {
2130 if (!path) { /* called from signal handler */
2131 pty_saved_jid = jid;
2133 pty_saved_jid = saved_jid;
2138 strncpy(saved_path, path, sizeof(wtmp.ut_tpath));
2139 strncpy(saved_user, user, sizeof(wtmp.ut_user));
2140 saved_path[sizeof(saved_path)] = '\0';
2141 saved_user[sizeof(saved_user)] = '\0';
2143 if (saved_jid == 0) {
2148 /* if the jid has changed, get the correct entry from the utmp file */
2150 if ( saved_jid != jid ) {
2151 struct utmp *utp = NULL;
2152 struct utmp *jid_getutid();
2154 utp = jid_getutid(pty_saved_jid);
2157 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
2161 cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
2165 cleantmpdir(jid, saved_path, saved_user);
2170 * Fork a child process to clean up the TMPDIR
2172 cleantmpdir(jid, tpath, user)
2174 register char *tpath;
2175 register char *user;
2179 syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
2183 execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0);
2184 syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
2185 tpath, CLEANTMPCMD);
2189 * Forget about child. We will exit, and
2190 * /etc/init will pick it up.
2196 #endif /* defined(PARENT_DOES_UTMP) && !defined(NEWINIT) */
2201 * This is the function called by cleanup() to
2202 * remove the utmp entry for this person.
2211 struct utmp *u, *utmp;
2215 struct utmpx *utxp, utmpx;
2218 * This updates the utmpx and utmp entries and make a wtmp/x entry
2221 SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1);
2222 utxp = getutxline(&utmpx);
2224 utxp->ut_type = DEAD_PROCESS;
2225 utxp->ut_exit.e_termination = 0;
2226 utxp->ut_exit.e_exit = 0;
2227 (void) time(&utmpx.ut_tv.tv_sec);
2228 utmpx.ut_tv.tv_usec = 0;
2235 #if !defined(UTMPX) && !(defined(CRAY) || defined(__hpux)) && BSD <= 43
2241 struct utmp *u, *utmp;
2245 f = open(utmpf, O_RDWR);
2247 (void) fstat(f, &statbf);
2248 utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
2250 syslog(LOG_ERR, "utmp malloc failed");
2251 if (statbf.st_size && utmp) {
2252 nutmp = read(f, (char *)utmp, (int)statbf.st_size);
2253 nutmp /= sizeof(struct utmp);
2255 for (u = utmp ; u < &utmp[nutmp] ; u++) {
2256 if (SCMPN(u->ut_line, line+5) ||
2259 (void) lseek(f, ((long)u)-((long)utmp), L_SET);
2260 SCPYN(u->ut_name, "");
2261 SCPYN(u->ut_host, "");
2262 (void) time(&u->ut_time);
2263 (void) write(f, (char *)u, sizeof(wtmp));
2270 f = open(wtmpf, O_WRONLY|O_APPEND);
2272 SCPYN(wtmp.ut_line, line+5);
2273 SCPYN(wtmp.ut_name, "");
2274 SCPYN(wtmp.ut_host, "");
2275 (void) time(&wtmp.ut_time);
2276 (void) write(f, (char *)&wtmp, sizeof(wtmp));
2280 (void) chmod(line, 0666);
2281 (void) chown(line, 0, 0);
2282 line[strlen("/dev/")] = 'p';
2283 (void) chmod(line, 0666);
2284 (void) chown(line, 0, 0);
2294 int fd; /* for /etc/wtmp */
2296 utmp.ut_type = USER_PROCESS;
2297 (void) strncpy(utmp.ut_id, line+12, sizeof(utmp.ut_id));
2299 utptr = getutid(&utmp);
2300 /* write it out only if it exists */
2302 utptr->ut_type = DEAD_PROCESS;
2303 utptr->ut_time = time((long *) 0);
2304 (void) pututline(utptr);
2305 /* set wtmp entry if wtmp file exists */
2306 if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
2307 (void) write(fd, utptr, sizeof(utmp));
2313 (void) chmod(line, 0666);
2314 (void) chown(line, 0, 0);
2315 line[14] = line[13];
2316 line[13] = line[12];
2322 (void) chmod(line, 0666);
2323 (void) chown(line, 0, 0);