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
36 RCSID("$Id: sys_term.c,v 1.104 2001/09/17 02:09:04 assar Exp $");
38 #if defined(_CRAY) || (defined(__hpux) && !defined(HAVE_UTMPX_H))
39 # define PARENT_DOES_UTMP
52 #elif defined(HAVE_UTMP_H)
54 #endif /* HAVE_UTMPX_H */
56 #ifdef HAVE_STRUCT_UTMP_UT_HOST
57 int utmp_len
= sizeof(wtmp
.ut_host
);
59 int utmp_len
= MaxHostNameLen
;
64 #define UTMP_FILE _PATH_UTMP
66 #define UTMP_FILE "/etc/utmp"
70 #if !defined(WTMP_FILE) && defined(_PATH_WTMP)
71 #define WTMP_FILE _PATH_WTMP
74 #ifndef PARENT_DOES_UTMP
76 char wtmpf
[] = WTMP_FILE
;
78 char wtmpf
[] = "/usr/adm/wtmp";
80 char utmpf
[] = UTMP_FILE
;
81 #else /* PARENT_DOES_UTMP */
83 char wtmpf
[] = WTMP_FILE
;
85 char wtmpf
[] = "/etc/wtmp";
87 #endif /* PARENT_DOES_UTMP */
99 #ifdef HAVE_SYS_STROPTS_H
100 #include <sys/stropts.h>
103 #endif /* STREAMSPTY */
107 #ifdef HAVE_SYS_STREAM_H
108 #ifdef HAVE_SYS_UIO_H
114 #include <sys/stream.h>
116 #if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY)
136 #ifdef HAVE_TERMIOS_H
147 #ifdef HAVE_LIBUTIL_H
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 */
183 static int ttyfd
= -1;
184 int really_stream
= 0;
187 const char *new_login
= _PATH_LOGIN
;
194 * These three routines are used to get and set the "termbuf" structure
195 * to and from the kernel. init_termbuf() gets the current settings.
196 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
197 * set_termbuf() writes the structure into the kernel.
205 tcgetattr(ttyfd
, &termbuf
);
208 tcgetattr(ourpty
, &termbuf
);
216 * Only make the necessary changes.
218 if (memcmp(&termbuf
, &termbuf2
, sizeof(termbuf
)))
221 tcsetattr(ttyfd
, TCSANOW
, &termbuf
);
224 tcsetattr(ourpty
, TCSANOW
, &termbuf
);
229 * spcset(func, valp, valpp)
231 * This function takes various special characters (func), and
232 * sets *valp to the current value of that character, and
233 * *valpp to point to where in the "termbuf" structure that
236 * It returns the SLC_ level of support for this function.
241 spcset(int func
, cc_t
*valp
, cc_t
**valpp
)
244 #define setval(a, b) *valp = termbuf.c_cc[a]; \
245 *valpp = &termbuf.c_cc[a]; \
247 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
251 setval(VEOF
, SLC_VARIABLE
);
253 setval(VERASE
, SLC_VARIABLE
);
255 setval(VKILL
, SLC_VARIABLE
);
257 setval(VINTR
, SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
259 setval(VQUIT
, SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
262 setval(VSTART
, SLC_VARIABLE
);
268 setval(VSTOP
, SLC_VARIABLE
);
274 setval(VWERASE
, SLC_VARIABLE
);
280 setval(VREPRINT
, SLC_VARIABLE
);
286 setval(VLNEXT
, SLC_VARIABLE
);
291 #if !defined(VDISCARD) && defined(VFLUSHO)
292 # define VDISCARD VFLUSHO
295 setval(VDISCARD
, SLC_VARIABLE
|SLC_FLUSHOUT
);
301 setval(VSUSP
, SLC_VARIABLE
|SLC_FLUSHIN
);
307 setval(VEOL
, SLC_VARIABLE
);
311 setval(VEOL2
, SLC_VARIABLE
);
315 setval(VSTATUS
, SLC_VARIABLE
);
328 return(SLC_NOSUPPORT
);
336 * Return the number of pty's configured into the system.
344 if ((numptys
= sysconf(_SC_CRAY_NPTY
)) != -1)
347 #endif /* _SC_CRAY_NPTY */
355 * Allocate a pty. As a side effect, the external character
356 * array "line" contains the name of the slave side.
358 * Returns the file descriptor of the opened pty.
361 static char Xline
[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
365 char myline
[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
368 #if !defined(HAVE_PTSNAME) && defined(STREAMSPTY)
369 static char *ptsname(int fd
)
379 int getpty(int *ptynum
)
381 #ifdef __osf__ /* XXX */
384 if(openpty(&master
, &slave
, line
, 0, 0) == 0){
393 p
= _getpty(&master
, O_RDWR
, 0600, 1);
396 strlcpy(line
, p
, sizeof(Xline
));
409 if(openpty(&master
, &slave
, line
, 0, 0) == 0){
415 char *clone
[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm",
416 "/dev/ptym/clone", 0 };
419 for(q
=clone
; *q
; q
++){
428 strlcpy(line
, ptsname(p
), sizeof(Xline
));
433 #endif /* STREAMSPTY */
437 snprintf(line
, sizeof(Xline
), "/dev/ptyXX");
441 snprintf(line
, sizeof(Xline
), "/dev/ptym/ptyXX");
447 for (cp
= "pqrstuvwxyzPQRST"; *cp
; cp
++) {
453 * This stat() check is just to keep us from
454 * looping through all 256 combinations if there
455 * aren't that many ptys available.
457 if (stat(line
, &stb
) < 0)
459 for (i
= 0; i
< 16; i
++) {
460 *p2
= "0123456789abcdef"[i
];
461 p
= open(line
, O_RDWR
);
466 for (p1
= &line
[8]; *p1
; p1
++)
473 if (ioctl(p
, TIOCGPGRP
, &dummy
) == 0
479 #endif /* SunOS == 40 */
485 extern lowpty
, highpty
;
488 for (*ptynum
= lowpty
; *ptynum
<= highpty
; (*ptynum
)++) {
489 snprintf(myline
, sizeof(myline
), "/dev/pty/%03d", *ptynum
);
493 snprintf(line
, sizeof(Xline
), "/dev/ttyp%03d", *ptynum
);
495 * Here are some shenanigans to make sure that there
496 * are no listeners lurking on the line.
498 if(stat(line
, &sb
) < 0) {
502 if(sb
.st_uid
|| sb
.st_gid
|| sb
.st_mode
!= 0600) {
511 * Now it should be safe...check for accessability.
513 if (access(line
, 6) == 0)
516 /* no tty side to pty so skip it */
521 #endif /* STREAMSPTY */
531 return (termbuf
.c_lflag
& ECHO
);
537 return((termbuf
.c_iflag
& IXON
) ? 1 : 0);
543 return((termbuf
.c_iflag
& IXANY
) ? 1 : 0);
550 termbuf
.c_lflag
|= ECHO
;
552 termbuf
.c_lflag
&= ~ECHO
;
558 return(!(termbuf
.c_lflag
& ICANON
));
565 termbuf
.c_iflag
&= ~ISTRIP
;
567 termbuf
.c_iflag
|= ISTRIP
;
572 tty_binaryout(int on
)
575 termbuf
.c_cflag
&= ~(CSIZE
|PARENB
);
576 termbuf
.c_cflag
|= CS8
;
577 termbuf
.c_oflag
&= ~OPOST
;
579 termbuf
.c_cflag
&= ~CSIZE
;
580 termbuf
.c_cflag
|= CS7
|PARENB
;
581 termbuf
.c_oflag
|= OPOST
;
588 return(!(termbuf
.c_iflag
& ISTRIP
));
592 tty_isbinaryout(void)
594 return(!(termbuf
.c_oflag
&OPOST
));
602 return (termbuf
.c_oflag
& OXTABS
);
605 return ((termbuf
.c_oflag
& TABDLY
) == TAB3
);
610 tty_setsofttab(int on
)
614 termbuf
.c_oflag
|= OXTABS
;
617 termbuf
.c_oflag
&= ~TABDLY
;
618 termbuf
.c_oflag
|= TAB3
;
622 termbuf
.c_oflag
&= ~OXTABS
;
625 termbuf
.c_oflag
&= ~TABDLY
;
626 termbuf
.c_oflag
|= TAB0
;
635 return (!(termbuf
.c_lflag
& ECHOCTL
));
638 return (!(termbuf
.c_lflag
& TCTLECH
));
640 # if !defined(ECHOCTL) && !defined(TCTLECH)
641 return (0); /* assumes ctl chars are echoed '^x' */
646 tty_setlitecho(int on
)
650 termbuf
.c_lflag
&= ~ECHOCTL
;
652 termbuf
.c_lflag
|= ECHOCTL
;
656 termbuf
.c_lflag
&= ~TCTLECH
;
658 termbuf
.c_lflag
|= TCTLECH
;
665 return (termbuf
.c_iflag
& ICRNL
);
669 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
678 * A table of available terminal speeds
684 { 0, B0
}, { 50, B50
}, { 75, B75
},
685 { 110, B110
}, { 134, B134
}, { 150, B150
},
686 { 200, B200
}, { 300, B300
}, { 600, B600
},
687 { 1200, B1200
}, { 1800, B1800
}, { 2400, B2400
},
716 #endif /* DECODE_BUAD */
722 struct termspeeds
*tp
;
724 for (tp
= termspeeds
; (tp
->speed
!= -1) && (val
> tp
->speed
); tp
++)
726 if (tp
->speed
== -1) /* back up to last valid value */
728 cfsetospeed(&termbuf
, tp
->value
);
729 #else /* DECODE_BUAD */
730 cfsetospeed(&termbuf
, val
);
731 #endif /* DECODE_BUAD */
738 struct termspeeds
*tp
;
740 for (tp
= termspeeds
; (tp
->speed
!= -1) && (val
> tp
->speed
); tp
++)
742 if (tp
->speed
== -1) /* back up to last valid value */
744 cfsetispeed(&termbuf
, tp
->value
);
745 #else /* DECODE_BAUD */
746 cfsetispeed(&termbuf
, val
);
747 #endif /* DECODE_BAUD */
750 #ifdef PARENT_DOES_UTMP
751 extern struct utmp wtmp
;
754 extern void utmp_sig_init (void);
755 extern void utmp_sig_reset (void);
756 extern void utmp_sig_wait (void);
757 extern void utmp_sig_notify (int);
758 # endif /* PARENT_DOES_UTMP */
762 /* I_FIND seems to live a life of its own */
763 static int my_find(int fd
, char *module
)
765 #if defined(I_FIND) && defined(I_LIST)
767 static struct str_list sl
;
772 n
= ioctl(fd
, I_LIST
, 0);
774 perror("ioctl(fd, I_LIST, 0)");
777 sl
.sl_modlist
=(struct str_mlist
*)malloc(n
* sizeof(struct str_mlist
));
779 n
= ioctl(fd
, I_LIST
, &sl
);
781 perror("ioctl(fd, I_LIST, n)");
787 for(i
=0; i
<sl
.sl_nmods
; i
++)
788 if(!strcmp(sl
.sl_modlist
[i
].l_name
, module
))
794 static void maybe_push_modules(int fd
, char **modules
)
799 for(p
=modules
; *p
; p
++){
800 err
= my_find(fd
, *p
);
803 if(err
< 0 && errno
!= EINVAL
)
804 fatalperror(net
, "my_find()");
805 /* module not pushed or does not exist */
807 /* p points to null or to an already pushed module, now push all
808 modules before this one */
810 for(p
--; p
>= modules
; p
--){
811 err
= ioctl(fd
, I_PUSH
, *p
);
812 if(err
< 0 && errno
!= EINVAL
)
813 fatalperror(net
, "I_PUSH");
821 * Open the slave side of the pty, and do any initialization
822 * that is necessary. The return value is a file descriptor
823 * for the slave side.
825 void getptyslave(void)
831 * Opening the slave side may cause initilization of the
832 * kernel tty structure. We need remember the state of
833 * if linemode was turned on
834 * terminal window size
836 * so that we can re-set them if we need to.
841 * Make sure that we don't have a controlling tty, and
842 * that we are the session (process group) leader.
847 fatalperror(net
, "setsid()");
850 t
= open(_PATH_TTY
, O_RDWR
);
852 ioctl(t
, TIOCNOTTY
, (char *)0);
858 # ifdef PARENT_DOES_UTMP
860 * Wait for our parent to get the utmp stuff to get done.
867 fatalperror(net
, line
);
874 * Not all systems have (or need) modules ttcompat and pckt so
875 * don't flag it as a fatal error if they don't exist.
880 /* these are the streams modules that we want pushed. note
881 that they are in reverse order, ptem will be pushed
882 first. maybe_push_modules() will try to push all modules
883 before the first one that isn't already pushed. i.e if
884 ldterm is pushed, only ttcompat will be attempted.
886 all this is because we don't know which modules are
887 available, and we don't know which modules are already
888 pushed (via autopush, for instance).
892 char *ttymodules
[] = { "ttcompat", "ldterm", "ptem", NULL
};
893 char *ptymodules
[] = { "pckt", NULL
};
895 maybe_push_modules(t
, ttymodules
);
896 maybe_push_modules(ourpty
, ptymodules
);
900 * set up the tty modes as we like them to be.
904 if (def_row
|| def_col
) {
905 memset(&ws
, 0, sizeof(ws
));
908 ioctl(t
, TIOCSWINSZ
, (char *)&ws
);
913 * Settings for sgtty based systems
917 * Settings for UNICOS (and HPUX)
919 # if defined(_CRAY) || defined(__hpux)
920 termbuf
.c_oflag
= OPOST
|ONLCR
|TAB3
;
921 termbuf
.c_iflag
= IGNPAR
|ISTRIP
|ICRNL
|IXON
;
922 termbuf
.c_lflag
= ISIG
|ICANON
|ECHO
|ECHOE
|ECHOK
;
923 termbuf
.c_cflag
= EXTB
|HUPCL
|CS8
;
927 * Settings for all other termios/termio based
928 * systems, other than 4.4BSD. In 4.4BSD the
929 * kernel does the initial terminal setup.
931 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43)
935 termbuf
.c_lflag
|= ECHO
;
936 termbuf
.c_oflag
|= ONLCR
|OXTABS
;
937 termbuf
.c_iflag
|= ICRNL
;
938 termbuf
.c_iflag
&= ~IXOFF
;
940 tty_rspeed((def_rspeed
> 0) ? def_rspeed
: 9600);
941 tty_tspeed((def_tspeed
> 0) ? def_tspeed
: 9600);
944 * Set the tty modes, and make this our controlling tty.
947 if (login_tty(t
) == -1)
948 fatalperror(net
, "login_tty");
961 * Open the specified slave side of the pty,
962 * making sure that we have a clean tty.
965 int cleanopen(char *line
)
974 * Make sure that other people can't open the
975 * slave side of the connection.
985 t
= open(line
, O_RDWR
|O_NOCTTY
);
991 * Hangup anybody else using this ttyp, then reopen it for
994 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
995 signal(SIGHUP
, SIG_IGN
);
1000 signal(SIGHUP
, SIG_DFL
);
1001 t
= open(line
, O_RDWR
|O_NOCTTY
);
1005 # if defined(_CRAY) && defined(TCVHUP)
1008 signal(SIGHUP
, SIG_IGN
);
1009 ioctl(t
, TCVHUP
, (char *)0);
1010 signal(SIGHUP
, SIG_DFL
);
1012 i
= open(line
, O_RDWR
);
1019 # endif /* defined(CRAY) && defined(TCVHUP) */
1023 #if !defined(BSD4_4)
1025 int login_tty(int t
)
1027 # if defined(TIOCSCTTY) && !defined(__hpux)
1028 if (ioctl(t
, TIOCSCTTY
, (char *)0) < 0)
1029 fatalperror(net
, "ioctl(sctty)");
1032 * Close the hard fd to /dev/ttypXXX, and re-open through
1033 * the indirect /dev/tty interface.
1036 if ((t
= open("/dev/tty", O_RDWR
)) < 0)
1037 fatalperror(net
, "open(/dev/tty)");
1041 * We get our controlling tty assigned as a side-effect
1042 * of opening up a tty device. But on BSD based systems,
1043 * this only happens if our process group is zero. The
1044 * setsid() call above may have set our pgrp, so clear
1045 * it out before opening the tty...
1050 setpgrp(0, 0); /* if setpgid isn't available, setpgrp
1051 probably takes arguments */
1053 close(open(line
, O_RDWR
));
1065 #endif /* BSD <= 43 */
1068 * This comes from ../../bsd/tty.c and should not really be here.
1072 * Clean the tty name. Return a pointer to the cleaned version.
1076 clean_ttyname (char *tty
)
1080 if (strncmp (res
, _PATH_DEV
, strlen(_PATH_DEV
)) == 0)
1081 res
+= strlen(_PATH_DEV
);
1082 if (strncmp (res
, "pty/", 4) == 0)
1084 if (strncmp (res
, "ptym/", 5) == 0)
1090 * Generate a name usable as an `ut_id', typically without `tty'.
1093 #ifdef HAVE_STRUCT_UTMP_UT_ID
1099 if (strncmp (res
, "pts/", 4) == 0)
1101 if (strncmp (res
, "tty", 3) == 0)
1110 * Given a hostname, do whatever
1111 * is necessary to startup the login process on the slave side of the pty.
1116 startslave(const char *host
, const char *utmp_host
,
1117 int autologin
, char *autoname
)
1121 #ifdef AUTHENTICATION
1122 if (!autoname
|| !autoname
[0])
1125 if (autologin
< auth_level
) {
1126 fatal(net
, "Authorization failed");
1133 "\r\n*** Connection not encrypted! "
1134 "Communication may be eavesdropped. ***\r\n";
1136 if (!no_warn
&& (encrypt_output
== 0 || decrypt_input
== 0))
1138 writenet((unsigned char*)tbuf
, strlen(tbuf
));
1140 # ifdef PARENT_DOES_UTMP
1142 # endif /* PARENT_DOES_UTMP */
1144 if ((i
= fork()) < 0)
1145 fatalperror(net
, "fork");
1147 # ifdef PARENT_DOES_UTMP
1149 * Cray parent will create utmp entry for child and send
1150 * signal to child to tell when done. Child waits for signal
1151 * before doing anything important.
1157 utmp_sig_reset(); /* reset handler to default */
1159 * Create utmp entry for child
1161 wtmp
.ut_time
= time(NULL
);
1162 wtmp
.ut_type
= LOGIN_PROCESS
;
1164 strncpy(wtmp
.ut_user
, "LOGIN", sizeof(wtmp
.ut_user
));
1165 strncpy(wtmp
.ut_host
, utmp_host
, sizeof(wtmp
.ut_host
));
1166 strncpy(wtmp
.ut_line
, clean_ttyname(line
), sizeof(wtmp
.ut_line
));
1167 #ifdef HAVE_STRUCT_UTMP_UT_ID
1168 strncpy(wtmp
.ut_id
, wtmp
.ut_line
+ 3, sizeof(wtmp
.ut_id
));
1173 if ((i
= open(wtmpf
, O_WRONLY
|O_APPEND
)) >= 0) {
1174 write(i
, &wtmp
, sizeof(struct utmp
));
1178 signal(WJSIGNAL
, sigjob
);
1180 utmp_sig_notify(pid
);
1181 # endif /* PARENT_DOES_UTMP */
1185 /* if we authenticated via K5, try and join the PAG */
1188 start_login(host
, autologin
, autoname
);
1194 extern char **environ
;
1202 if ((*envp
= getenv("TZ")))
1204 #if defined(_CRAY) || defined(__hpux)
1206 *envp
++ = "TZ=GMT0";
1215 * We only accept the environment variables listed below.
1221 static const char *reject
[] = {
1226 static const char *accept
[] = {
1227 "XAUTH=", "XAUTHORITY=", "DISPLAY=",
1240 char ** new_environ
;
1243 /* Allocate space for scrubbed environment. */
1244 for (count
= 1, cpp
= environ
; *cpp
; count
++, cpp
++)
1246 if ((new_environ
= malloc(count
* sizeof(char *))) == NULL
) {
1251 for (cpp2
= new_environ
, cpp
= environ
; *cpp
; cpp
++) {
1254 for(p
= reject
; *p
; p
++)
1255 if(strncmp(*cpp
, *p
, strlen(*p
)) == 0) {
1262 for(p
= accept
; *p
; p
++)
1263 if(strncmp(*cpp
, *p
, strlen(*p
)) == 0)
1266 if ((*cpp2
++ = strdup(*cpp
)) == NULL
) {
1267 environ
= new_environ
;
1273 environ
= new_environ
;
1283 static void addarg(struct arg_val
*, const char*);
1288 * Assuming that we are now running as a child processes, this
1289 * function will turn us into the login process.
1293 start_login(const char *host
, int autologin
, char *name
)
1295 struct arg_val argv
;
1305 * Create utmp entry for child
1308 clean_tty
= clean_ttyname(line
);
1309 memset(&utmpx
, 0, sizeof(utmpx
));
1310 strncpy(utmpx
.ut_user
, ".telnet", sizeof(utmpx
.ut_user
));
1311 strncpy(utmpx
.ut_line
, clean_tty
, sizeof(utmpx
.ut_line
));
1312 #ifdef HAVE_STRUCT_UTMP_UT_ID
1313 strncpy(utmpx
.ut_id
, make_id(clean_tty
), sizeof(utmpx
.ut_id
));
1317 utmpx
.ut_type
= LOGIN_PROCESS
;
1319 gettimeofday (&utmpx
.ut_tv
, NULL
);
1320 if (pututxline(&utmpx
) == NULL
)
1321 fatal(net
, "pututxline failed");
1327 * -h : pass on name of host.
1328 * WARNING: -h is accepted by login if and only if
1330 * -p : don't clobber the environment (so terminal type stays set).
1332 * -f : force this login, he has already been authenticated
1335 /* init argv structure */
1338 argv
.argv
=malloc(0); /*so we can call realloc later */
1339 addarg(&argv
, "login");
1340 addarg(&argv
, "-h");
1341 addarg(&argv
, host
);
1342 addarg(&argv
, "-p");
1346 user
= getenv("USER");
1347 #ifdef AUTHENTICATION
1348 if (auth_level
< 0 || autologin
!= AUTH_VALID
) {
1350 printf("User not authenticated. ");
1352 printf("Using one-time password\r\n");
1354 printf("Using plaintext username and password\r\n");
1357 addarg(&argv
, "-a");
1358 addarg(&argv
, "otp");
1361 syslog(LOG_INFO
, "unauthenticated access from %s (%s)",
1362 host
, user
? user
: "unknown user");
1364 if (auth_level
>= 0 && autologin
== AUTH_VALID
)
1365 addarg(&argv
, "-f");
1368 addarg(&argv
, "--");
1369 addarg(&argv
, strdup(user
));
1371 if (getenv("USER")) {
1373 * Assume that login will set the USER variable
1374 * correctly. For SysV systems, this means that
1375 * USER will no longer be set, just LOGNAME by
1376 * login. (The problem is that if the auto-login
1377 * fails, and the user then specifies a different
1378 * account name, he can get logged in with both
1379 * LOGNAME and USER in his environment, but the
1380 * USER value will be wrong.
1386 * This sleep(1) is in here so that telnetd can
1387 * finish up with the tty. There's a race condition
1388 * the login banner message gets lost...
1392 execv(new_login
, argv
.argv
);
1394 syslog(LOG_ERR
, "%s: %m\n", new_login
);
1395 fatalperror_errno(net
, new_login
, save_errno
);
1400 addarg(struct arg_val
*argv
, const char *val
)
1402 if(argv
->size
<= argv
->argc
+1) {
1403 argv
->argv
= realloc(argv
->argv
, sizeof(char*) * (argv
->size
+ 10));
1404 if (argv
->argv
== NULL
)
1405 fatal (net
, "realloc: out of memory");
1408 argv
->argv
[argv
->argc
++] = val
;
1409 argv
->argv
[argv
->argc
] = NULL
;
1416 * This is the function called by cleanup() to
1417 * remove the utmp entry for this person.
1424 struct utmpx utmpx
, *non_save_utxp
;
1425 char *clean_tty
= clean_ttyname(line
);
1428 * This updates the utmpx and utmp entries and make a wtmp/x entry
1432 memset(&utmpx
, 0, sizeof(utmpx
));
1433 strncpy(utmpx
.ut_line
, clean_tty
, sizeof(utmpx
.ut_line
));
1434 utmpx
.ut_type
= LOGIN_PROCESS
;
1435 non_save_utxp
= getutxline(&utmpx
);
1436 if (non_save_utxp
) {
1440 utxp
= malloc(sizeof(struct utmpx
));
1441 *utxp
= *non_save_utxp
;
1442 user0
= utxp
->ut_user
[0];
1443 utxp
->ut_user
[0] = '\0';
1444 utxp
->ut_type
= DEAD_PROCESS
;
1445 #ifdef HAVE_STRUCT_UTMPX_UT_EXIT
1446 #ifdef _STRUCT___EXIT_STATUS
1447 utxp
->ut_exit
.__e_termination
= 0;
1448 utxp
->ut_exit
.__e_exit
= 0;
1449 #elif defined(__osf__) /* XXX */
1450 utxp
->ut_exit
.ut_termination
= 0;
1451 utxp
->ut_exit
.ut_exit
= 0;
1453 utxp
->ut_exit
.e_termination
= 0;
1454 utxp
->ut_exit
.e_exit
= 0;
1457 gettimeofday(&utxp
->ut_tv
, NULL
);
1460 utxp
->ut_user
[0] = user0
;
1461 updwtmpx(WTMPX_FILE
, utxp
);
1462 #elif defined(WTMP_FILE)
1463 /* This is a strange system with a utmpx and a wtmp! */
1465 int f
= open(wtmpf
, O_WRONLY
|O_APPEND
);
1468 strncpy(wtmp
.ut_line
, clean_tty
, sizeof(wtmp
.ut_line
));
1469 strncpy(wtmp
.ut_name
, "", sizeof(wtmp
.ut_name
));
1470 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1471 strncpy(wtmp
.ut_host
, "", sizeof(wtmp
.ut_host
));
1473 wtmp
.ut_time
= time(NULL
);
1474 write(f
, &wtmp
, sizeof(wtmp
));
1485 #if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43
1491 struct utmp
*u
, *utmp
;
1494 char *clean_tty
= clean_ttyname(line
);
1496 f
= open(utmpf
, O_RDWR
);
1499 utmp
= (struct utmp
*)malloc((unsigned)statbf
.st_size
);
1501 syslog(LOG_ERR
, "utmp malloc failed");
1502 if (statbf
.st_size
&& utmp
) {
1503 nutmp
= read(f
, utmp
, (int)statbf
.st_size
);
1504 nutmp
/= sizeof(struct utmp
);
1506 for (u
= utmp
; u
< &utmp
[nutmp
] ; u
++) {
1507 if (strncmp(u
->ut_line
,
1509 sizeof(u
->ut_line
)) ||
1512 lseek(f
, ((long)u
)-((long)utmp
), L_SET
);
1513 strncpy(u
->ut_name
, "", sizeof(u
->ut_name
));
1514 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1515 strncpy(u
->ut_host
, "", sizeof(u
->ut_host
));
1517 u
->ut_time
= time(NULL
);
1518 write(f
, u
, sizeof(wtmp
));
1525 f
= open(wtmpf
, O_WRONLY
|O_APPEND
);
1527 strncpy(wtmp
.ut_line
, clean_tty
, sizeof(wtmp
.ut_line
));
1528 strncpy(wtmp
.ut_name
, "", sizeof(wtmp
.ut_name
));
1529 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1530 strncpy(wtmp
.ut_host
, "", sizeof(wtmp
.ut_host
));
1532 wtmp
.ut_time
= time(NULL
);
1533 write(f
, &wtmp
, sizeof(wtmp
));
1539 line
[strlen("/dev/")] = 'p';
1545 #if defined(__hpux) && !defined(HAVE_UTMPX_H)
1551 int fd
; /* for /etc/wtmp */
1553 utmp
.ut_type
= USER_PROCESS
;
1554 strncpy(utmp
.ut_line
, clean_ttyname(line
), sizeof(utmp
.ut_line
));
1556 utptr
= getutline(&utmp
);
1557 /* write it out only if it exists */
1559 utptr
->ut_type
= DEAD_PROCESS
;
1560 utptr
->ut_time
= time(NULL
);
1562 /* set wtmp entry if wtmp file exists */
1563 if ((fd
= open(wtmpf
, O_WRONLY
| O_APPEND
)) >= 0) {
1564 write(fd
, utptr
, sizeof(utmp
));
1572 line
[14] = line
[13];
1573 line
[13] = line
[12];
1587 * This is the routine to call when we are all through, to
1588 * clean up anything that needs to be cleaned up.
1591 #ifdef PARENT_DOES_UTMP
1597 static int incleanup
= 0;
1599 int child_status
; /* status of child process as returned by waitpid */
1600 int flags
= WNOHANG
|WUNTRACED
;
1603 * 1: Pick up the zombie, if we are being called
1604 * as the signal handler.
1605 * 2: If we are a nested cleanup(), return.
1606 * 3: Try to clean up TMPDIR.
1607 * 4: Fill in utmp with shutdown of process.
1608 * 5: Close down the network and pty connections.
1609 * 6: Finish up the TMPDIR cleanup, if needed.
1611 if (sig
== SIGCHLD
) {
1612 while (waitpid(-1, &child_status
, flags
) > 0)
1614 /* Check if the child process was stopped
1615 * rather than exited. We want cleanup only if
1616 * the child has died.
1618 if (WIFSTOPPED(child_status
)) {
1622 t
= sigblock(sigmask(SIGCHLD
));
1630 t
= cleantmp(&wtmp
);
1631 setutent(); /* just to make sure */
1643 #else /* PARENT_DOES_UTMP */
1648 #if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)
1652 vhangup(); /* XXX */
1658 p
= line
+ sizeof("/dev/") - 1;
1671 #endif /* PARENT_DOES_UTMP */
1673 #ifdef PARENT_DOES_UTMP
1678 * These three functions are used to coordinate the handling of
1679 * the utmp file between the server and the soon-to-be-login shell.
1680 * The server actually creates the utmp structure, the child calls
1681 * utmp_sig_wait(), until the server calls utmp_sig_notify() and
1682 * signals the future-login shell to proceed.
1684 static int caught
=0; /* NZ when signal intercepted */
1685 static void (*func
)(); /* address of previous handler */
1692 signal(SIGUSR1
, func
);
1699 * register signal handler for UTMP creation
1701 if ((int)(func
= signal(SIGUSR1
, _utmp_sig_rcv
)) == -1)
1702 fatalperror(net
, "telnetd/signal");
1708 signal(SIGUSR1
, func
); /* reset handler to default */
1712 # define sigoff() /* do nothing */
1713 # define sigon() /* do nothing */
1720 * Wait for parent to write our utmp entry.
1723 while (caught
== 0) {
1724 pause(); /* wait until we get a signal (sigon) */
1725 sigoff(); /* turn off signals while we check caught */
1727 sigon(); /* turn on signals again */
1731 utmp_sig_notify(pid
)
1737 static int gotsigjob
= 0;
1747 while ((jid
= waitjob(NULL
)) != -1) {
1752 jobend(jid
, NULL
, NULL
);
1758 * called by jobend() before calling cleantmp()
1759 * to find the correct $TMPDIR to cleanup.
1766 struct utmp
*cur
= NULL
;
1768 setutent(); /* just to make sure */
1769 while (cur
= getutent()) {
1770 if ( (cur
->ut_type
!= NULL
) && (jid
== cur
->ut_jid
) ) {
1779 * Clean up the TMPDIR that login created.
1780 * The first time this is called we pick up the info
1781 * from the utmp. If the job has already gone away,
1782 * then we'll clean up and be done. If not, then
1783 * when this is called the second time it will wait
1784 * for the signal that the job is done.
1791 static int first
= 1;
1792 int mask
, omask
, ret
;
1793 extern struct utmp
*getutid (const struct utmp
*_Id
);
1796 mask
= sigmask(WJSIGNAL
);
1799 omask
= sigblock(mask
);
1800 while (gotsigjob
== 0)
1805 setutent(); /* just to make sure */
1809 syslog(LOG_ERR
, "Can't get /etc/utmp entry to clean TMPDIR");
1813 * Nothing to clean up if the user shell was never started.
1815 if (utp
->ut_type
!= USER_PROCESS
|| utp
->ut_jid
== 0)
1819 * Block the WJSIGNAL while we are in jobend().
1821 omask
= sigblock(mask
);
1822 ret
= jobend(utp
->ut_jid
, utp
->ut_tpath
, utp
->ut_user
);
1828 jobend(jid
, path
, user
)
1833 static int saved_jid
= 0;
1834 static int pty_saved_jid
= 0;
1835 static char saved_path
[sizeof(wtmp
.ut_tpath
)+1];
1836 static char saved_user
[sizeof(wtmp
.ut_user
)+1];
1839 * this little piece of code comes into play
1840 * only when ptyreconnect is used to reconnect
1841 * to an previous session.
1843 * this is the only time when the
1844 * "saved_jid != jid" code is executed.
1847 if ( saved_jid
&& saved_jid
!= jid
) {
1848 if (!path
) { /* called from signal handler */
1849 pty_saved_jid
= jid
;
1851 pty_saved_jid
= saved_jid
;
1856 strncpy(saved_path
, path
, sizeof(wtmp
.ut_tpath
));
1857 strncpy(saved_user
, user
, sizeof(wtmp
.ut_user
));
1858 saved_path
[sizeof(saved_path
)] = '\0';
1859 saved_user
[sizeof(saved_user
)] = '\0';
1861 if (saved_jid
== 0) {
1866 /* if the jid has changed, get the correct entry from the utmp file */
1868 if ( saved_jid
!= jid
) {
1869 struct utmp
*utp
= NULL
;
1870 struct utmp
*jid_getutid();
1872 utp
= jid_getutid(pty_saved_jid
);
1875 syslog(LOG_ERR
, "Can't get /etc/utmp entry to clean TMPDIR");
1879 cleantmpdir(jid
, utp
->ut_tpath
, utp
->ut_user
);
1883 cleantmpdir(jid
, saved_path
, saved_user
);
1888 * Fork a child process to clean up the TMPDIR
1890 cleantmpdir(jid
, tpath
, user
)
1897 syslog(LOG_ERR
, "TMPDIR cleanup(%s): fork() failed: %m\n",
1901 execl(CLEANTMPCMD
, CLEANTMPCMD
, user
, tpath
, 0);
1902 syslog(LOG_ERR
, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1903 tpath
, CLEANTMPCMD
);
1907 * Forget about child. We will exit, and
1908 * /etc/init will pick it up.
1914 #endif /* defined(PARENT_DOES_UTMP) */