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("$Heimdal: sys_term.c 22390 2007-12-31 10:12:48Z lha $"
39 #if defined(_CRAY) || (defined(__hpux) && !defined(HAVE_UTMPX_H))
40 # define PARENT_DOES_UTMP
53 #elif defined(HAVE_UTMP_H)
55 #endif /* HAVE_UTMPX_H */
57 #ifdef HAVE_STRUCT_UTMP_UT_HOST
58 int utmp_len
= sizeof(wtmp
.ut_host
);
60 int utmp_len
= MaxHostNameLen
;
65 #define UTMP_FILE _PATH_UTMP
67 #define UTMP_FILE "/etc/utmp"
71 #if !defined(WTMP_FILE) && defined(_PATH_WTMP)
72 #define WTMP_FILE _PATH_WTMP
75 #ifndef PARENT_DOES_UTMP
77 char wtmpf
[] = WTMP_FILE
;
79 char wtmpf
[] = "/usr/adm/wtmp";
81 char utmpf
[] = UTMP_FILE
;
82 #else /* PARENT_DOES_UTMP */
84 char wtmpf
[] = WTMP_FILE
;
86 char wtmpf
[] = "/etc/wtmp";
88 #endif /* PARENT_DOES_UTMP */
94 #if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY)
114 #ifdef HAVE_TERMIOS_H
125 #ifdef HAVE_LIBUTIL_H
131 # define TCSANOW TCSETS
132 # define TCSADRAIN TCSETSW
133 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
136 # define TCSANOW TCSETA
137 # define TCSADRAIN TCSETAW
138 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
140 # define TCSANOW TIOCSETA
141 # define TCSADRAIN TIOCSETAW
142 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
145 # define tcsetattr(f, a, t) ioctl(f, a, t)
146 # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
147 (tp)->c_cflag |= (val)
148 # define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
150 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
151 (tp)->c_cflag |= ((val)<<IBSHIFT)
152 # define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
154 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
155 (tp)->c_cflag |= (val)
156 # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
158 # endif /* TCSANOW */
159 struct termios termbuf
, termbuf2
; /* pty control structure */
161 static int ttyfd
= -1;
162 int really_stream
= 0;
165 const char *new_login
= _PATH_LOGIN
;
172 * These three routines are used to get and set the "termbuf" structure
173 * to and from the kernel. init_termbuf() gets the current settings.
174 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
175 * set_termbuf() writes the structure into the kernel.
183 tcgetattr(ttyfd
, &termbuf
);
186 tcgetattr(ourpty
, &termbuf
);
194 * Only make the necessary changes.
196 if (memcmp(&termbuf
, &termbuf2
, sizeof(termbuf
))) {
199 tcsetattr(ttyfd
, TCSANOW
, &termbuf
);
202 tcsetattr(ourpty
, TCSANOW
, &termbuf
);
208 * spcset(func, valp, valpp)
210 * This function takes various special characters (func), and
211 * sets *valp to the current value of that character, and
212 * *valpp to point to where in the "termbuf" structure that
215 * It returns the SLC_ level of support for this function.
220 spcset(int func
, cc_t
*valp
, cc_t
**valpp
)
223 #define setval(a, b) *valp = termbuf.c_cc[a]; \
224 *valpp = &termbuf.c_cc[a]; \
226 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
230 setval(VEOF
, SLC_VARIABLE
);
232 setval(VERASE
, SLC_VARIABLE
);
234 setval(VKILL
, SLC_VARIABLE
);
236 setval(VINTR
, SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
238 setval(VQUIT
, SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
241 setval(VSTART
, SLC_VARIABLE
);
247 setval(VSTOP
, SLC_VARIABLE
);
253 setval(VWERASE
, SLC_VARIABLE
);
259 setval(VREPRINT
, SLC_VARIABLE
);
265 setval(VLNEXT
, SLC_VARIABLE
);
270 #if !defined(VDISCARD) && defined(VFLUSHO)
271 # define VDISCARD VFLUSHO
274 setval(VDISCARD
, SLC_VARIABLE
|SLC_FLUSHOUT
);
280 setval(VSUSP
, SLC_VARIABLE
|SLC_FLUSHIN
);
286 setval(VEOL
, SLC_VARIABLE
);
290 setval(VEOL2
, SLC_VARIABLE
);
294 setval(VSTATUS
, SLC_VARIABLE
);
307 return(SLC_NOSUPPORT
);
315 * Return the number of pty's configured into the system.
323 if ((numptys
= sysconf(_SC_CRAY_NPTY
)) != -1)
326 #endif /* _SC_CRAY_NPTY */
334 * Allocate a pty. As a side effect, the external character
335 * array "line" contains the name of the slave side.
337 * Returns the file descriptor of the opened pty.
340 static int ptyslavefd
= -1;
342 static char Xline
[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
346 char myline
[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
349 #if !defined(HAVE_PTSNAME) && defined(STREAMSPTY)
350 static char *ptsname(int fd
)
360 int getpty(int *ptynum
)
362 #if defined(HAVE_OPENPTY) || defined(__linux) || defined(__osf__) /* XXX */
366 if(openpty(&master
, &slave
, line
, 0, 0) == 0){
371 #endif /* HAVE_OPENPTY .... */
376 p
= _getpty(&master
, O_RDWR
, 0600, 1);
379 strlcpy(line
, p
, sizeof(Xline
));
386 char *clone
[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm",
387 "/dev/ptym/clone", 0 };
391 for(q
=clone
; *q
; q
++){
400 strlcpy(line
, ptsname(p
), sizeof(Xline
));
406 #endif /* STREAMSPTY */
414 snprintf(line
, sizeof(Xline
), "/dev/ptyXX");
418 snprintf(line
, sizeof(Xline
), "/dev/ptym/ptyXX");
424 for (cp
= "pqrstuvwxyzPQRST"; *cp
; cp
++) {
430 * This stat() check is just to keep us from
431 * looping through all 256 combinations if there
432 * aren't that many ptys available.
434 if (stat(line
, &stb
) < 0)
436 for (i
= 0; i
< 16; i
++) {
437 *p2
= "0123456789abcdef"[i
];
438 p
= open(line
, O_RDWR
);
447 for (p1
= &line
[8]; *p1
; p1
++)
454 if (ioctl(p
, TIOCGPGRP
, &dummy
) == 0
460 #endif /* SunOS == 40 */
468 extern lowpty
, highpty
;
472 for (*ptynum
= lowpty
; *ptynum
<= highpty
; (*ptynum
)++) {
473 snprintf(myline
, sizeof(myline
), "/dev/pty/%03d", *ptynum
);
477 snprintf(line
, sizeof(Xline
), "/dev/ttyp%03d", *ptynum
);
479 * Here are some shenanigans to make sure that there
480 * are no listeners lurking on the line.
482 if(stat(line
, &sb
) < 0) {
486 if(sb
.st_uid
|| sb
.st_gid
|| sb
.st_mode
!= 0600) {
495 * Now it should be safe...check for accessability.
497 if (access(line
, 6) == 0)
500 /* no tty side to pty so skip it */
513 return (termbuf
.c_lflag
& ECHO
);
519 return((termbuf
.c_iflag
& IXON
) ? 1 : 0);
525 return((termbuf
.c_iflag
& IXANY
) ? 1 : 0);
532 termbuf
.c_lflag
|= ECHO
;
534 termbuf
.c_lflag
&= ~ECHO
;
540 return(!(termbuf
.c_lflag
& ICANON
));
547 termbuf
.c_iflag
&= ~ISTRIP
;
549 termbuf
.c_iflag
|= ISTRIP
;
554 tty_binaryout(int on
)
557 termbuf
.c_cflag
&= ~(CSIZE
|PARENB
);
558 termbuf
.c_cflag
|= CS8
;
559 termbuf
.c_oflag
&= ~OPOST
;
561 termbuf
.c_cflag
&= ~CSIZE
;
562 termbuf
.c_cflag
|= CS7
|PARENB
;
563 termbuf
.c_oflag
|= OPOST
;
570 return(!(termbuf
.c_iflag
& ISTRIP
));
574 tty_isbinaryout(void)
576 return(!(termbuf
.c_oflag
&OPOST
));
584 return (termbuf
.c_oflag
& OXTABS
);
587 return ((termbuf
.c_oflag
& TABDLY
) == TAB3
);
592 tty_setsofttab(int on
)
596 termbuf
.c_oflag
|= OXTABS
;
599 termbuf
.c_oflag
&= ~TABDLY
;
600 termbuf
.c_oflag
|= TAB3
;
604 termbuf
.c_oflag
&= ~OXTABS
;
607 termbuf
.c_oflag
&= ~TABDLY
;
608 termbuf
.c_oflag
|= TAB0
;
617 return (!(termbuf
.c_lflag
& ECHOCTL
));
620 return (!(termbuf
.c_lflag
& TCTLECH
));
622 # if !defined(ECHOCTL) && !defined(TCTLECH)
623 return (0); /* assumes ctl chars are echoed '^x' */
628 tty_setlitecho(int on
)
632 termbuf
.c_lflag
&= ~ECHOCTL
;
634 termbuf
.c_lflag
|= ECHOCTL
;
638 termbuf
.c_lflag
&= ~TCTLECH
;
640 termbuf
.c_lflag
|= TCTLECH
;
647 return (termbuf
.c_iflag
& ICRNL
);
651 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
660 * A table of available terminal speeds
666 { 0, B0
}, { 50, B50
}, { 75, B75
},
667 { 110, B110
}, { 134, B134
}, { 150, B150
},
668 { 200, B200
}, { 300, B300
}, { 600, B600
},
669 { 1200, B1200
}, { 1800, B1800
}, { 2400, B2400
},
698 #endif /* DECODE_BUAD */
704 struct termspeeds
*tp
;
706 for (tp
= termspeeds
; (tp
->speed
!= -1) && (val
> tp
->speed
); tp
++)
708 if (tp
->speed
== -1) /* back up to last valid value */
710 cfsetospeed(&termbuf
, tp
->value
);
711 #else /* DECODE_BUAD */
712 cfsetospeed(&termbuf
, val
);
713 #endif /* DECODE_BUAD */
720 struct termspeeds
*tp
;
722 for (tp
= termspeeds
; (tp
->speed
!= -1) && (val
> tp
->speed
); tp
++)
724 if (tp
->speed
== -1) /* back up to last valid value */
726 cfsetispeed(&termbuf
, tp
->value
);
727 #else /* DECODE_BAUD */
728 cfsetispeed(&termbuf
, val
);
729 #endif /* DECODE_BAUD */
732 #ifdef PARENT_DOES_UTMP
733 extern struct utmp wtmp
;
736 extern void utmp_sig_init (void);
737 extern void utmp_sig_reset (void);
738 extern void utmp_sig_wait (void);
739 extern void utmp_sig_notify (int);
740 # endif /* PARENT_DOES_UTMP */
744 /* I_FIND seems to live a life of its own */
745 static int my_find(int fd
, char *module
)
747 #if defined(I_FIND) && defined(I_LIST)
749 static struct str_list sl
;
754 n
= ioctl(fd
, I_LIST
, 0);
756 perror("ioctl(fd, I_LIST, 0)");
759 sl
.sl_modlist
=(struct str_mlist
*)malloc(n
* sizeof(struct str_mlist
));
761 n
= ioctl(fd
, I_LIST
, &sl
);
763 perror("ioctl(fd, I_LIST, n)");
769 for(i
=0; i
<sl
.sl_nmods
; i
++)
770 if(!strcmp(sl
.sl_modlist
[i
].l_name
, module
))
776 static void maybe_push_modules(int fd
, char **modules
)
781 for(p
=modules
; *p
; p
++){
782 err
= my_find(fd
, *p
);
785 if(err
< 0 && errno
!= EINVAL
)
786 fatalperror(net
, "my_find()");
787 /* module not pushed or does not exist */
789 /* p points to null or to an already pushed module, now push all
790 modules before this one */
792 for(p
--; p
>= modules
; p
--){
793 err
= ioctl(fd
, I_PUSH
, *p
);
794 if(err
< 0 && errno
!= EINVAL
)
795 fatalperror(net
, "I_PUSH");
803 * Open the slave side of the pty, and do any initialization
804 * that is necessary. The return value is a file descriptor
805 * for the slave side.
807 void getptyslave(void)
813 * Opening the slave side may cause initilization of the
814 * kernel tty structure. We need remember the state of
815 * if linemode was turned on
816 * terminal window size
818 * so that we can re-set them if we need to.
823 * Make sure that we don't have a controlling tty, and
824 * that we are the session (process group) leader.
829 fatalperror(net
, "setsid()");
832 t
= open(_PATH_TTY
, O_RDWR
);
834 ioctl(t
, TIOCNOTTY
, (char *)0);
840 # ifdef PARENT_DOES_UTMP
842 * Wait for our parent to get the utmp stuff to get done.
849 fatalperror(net
, line
);
856 * Not all systems have (or need) modules ttcompat and pckt so
857 * don't flag it as a fatal error if they don't exist.
862 /* these are the streams modules that we want pushed. note
863 that they are in reverse order, ptem will be pushed
864 first. maybe_push_modules() will try to push all modules
865 before the first one that isn't already pushed. i.e if
866 ldterm is pushed, only ttcompat will be attempted.
868 all this is because we don't know which modules are
869 available, and we don't know which modules are already
870 pushed (via autopush, for instance).
874 char *ttymodules
[] = { "ttcompat", "ldterm", "ptem", NULL
};
875 char *ptymodules
[] = { "pckt", NULL
};
877 maybe_push_modules(t
, ttymodules
);
878 maybe_push_modules(ourpty
, ptymodules
);
882 * set up the tty modes as we like them to be.
886 if (def_row
|| def_col
) {
887 memset(&ws
, 0, sizeof(ws
));
890 ioctl(t
, TIOCSWINSZ
, (char *)&ws
);
895 * Settings for sgtty based systems
899 * Settings for UNICOS (and HPUX)
901 # if defined(_CRAY) || defined(__hpux)
902 termbuf
.c_oflag
= OPOST
|ONLCR
|TAB3
;
903 termbuf
.c_iflag
= IGNPAR
|ISTRIP
|ICRNL
|IXON
;
904 termbuf
.c_lflag
= ISIG
|ICANON
|ECHO
|ECHOE
|ECHOK
;
905 termbuf
.c_cflag
= EXTB
|HUPCL
|CS8
;
909 * Settings for all other termios/termio based
910 * systems, other than 4.4BSD. In 4.4BSD the
911 * kernel does the initial terminal setup.
913 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43)
917 termbuf
.c_lflag
|= ECHO
;
918 termbuf
.c_oflag
|= ONLCR
|OXTABS
;
919 termbuf
.c_iflag
|= ICRNL
;
920 termbuf
.c_iflag
&= ~IXOFF
;
922 tty_rspeed((def_rspeed
> 0) ? def_rspeed
: 9600);
923 tty_tspeed((def_tspeed
> 0) ? def_tspeed
: 9600);
926 * Set the tty modes, and make this our controlling tty.
929 if (login_tty(t
) == -1)
930 fatalperror(net
, "login_tty");
943 * Open the specified slave side of the pty,
944 * making sure that we have a clean tty.
947 int cleanopen(char *line
)
951 if (ptyslavefd
!= -1)
959 * Make sure that other people can't open the
960 * slave side of the connection.
970 t
= open(line
, O_RDWR
|O_NOCTTY
);
976 * Hangup anybody else using this ttyp, then reopen it for
979 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
980 signal(SIGHUP
, SIG_IGN
);
985 signal(SIGHUP
, SIG_DFL
);
986 t
= open(line
, O_RDWR
|O_NOCTTY
);
990 # if defined(_CRAY) && defined(TCVHUP)
993 signal(SIGHUP
, SIG_IGN
);
994 ioctl(t
, TCVHUP
, (char *)0);
995 signal(SIGHUP
, SIG_DFL
);
997 i
= open(line
, O_RDWR
);
1004 # endif /* defined(CRAY) && defined(TCVHUP) */
1008 #if !defined(BSD4_4)
1010 int login_tty(int t
)
1012 # if defined(TIOCSCTTY) && !defined(__hpux)
1013 if (ioctl(t
, TIOCSCTTY
, (char *)0) < 0)
1014 fatalperror(net
, "ioctl(sctty)");
1017 * Close the hard fd to /dev/ttypXXX, and re-open through
1018 * the indirect /dev/tty interface.
1021 if ((t
= open("/dev/tty", O_RDWR
)) < 0)
1022 fatalperror(net
, "open(/dev/tty)");
1026 * We get our controlling tty assigned as a side-effect
1027 * of opening up a tty device. But on BSD based systems,
1028 * this only happens if our process group is zero. The
1029 * setsid() call above may have set our pgrp, so clear
1030 * it out before opening the tty...
1035 setpgrp(0, 0); /* if setpgid isn't available, setpgrp
1036 probably takes arguments */
1038 close(open(line
, O_RDWR
));
1050 #endif /* BSD <= 43 */
1053 * This comes from ../../bsd/tty.c and should not really be here.
1057 * Clean the tty name. Return a pointer to the cleaned version.
1060 static char * clean_ttyname (char *) __attribute__((unused
));
1063 clean_ttyname (char *tty
)
1067 if (strncmp (res
, _PATH_DEV
, strlen(_PATH_DEV
)) == 0)
1068 res
+= strlen(_PATH_DEV
);
1069 if (strncmp (res
, "pty/", 4) == 0)
1071 if (strncmp (res
, "ptym/", 5) == 0)
1077 * Generate a name usable as an `ut_id', typically without `tty'.
1080 #ifdef HAVE_STRUCT_UTMP_UT_ID
1086 if (strncmp (res
, "pts/", 4) == 0)
1088 if (strncmp (res
, "tty", 3) == 0)
1097 * Given a hostname, do whatever
1098 * is necessary to startup the login process on the slave side of the pty.
1103 startslave(const char *host
, const char *utmp_host
,
1104 int autologin
, char *autoname
)
1108 #ifdef AUTHENTICATION
1109 if (!autoname
|| !autoname
[0])
1112 if (autologin
< auth_level
) {
1113 fatal(net
, "Authorization failed");
1120 "\r\n*** Connection not encrypted! "
1121 "Communication may be eavesdropped. ***\r\n";
1123 if (!no_warn
&& (encrypt_output
== 0 || decrypt_input
== 0))
1125 writenet(tbuf
, strlen(tbuf
));
1127 # ifdef PARENT_DOES_UTMP
1129 # endif /* PARENT_DOES_UTMP */
1131 if ((i
= fork()) < 0)
1132 fatalperror(net
, "fork");
1134 # ifdef PARENT_DOES_UTMP
1136 * Cray parent will create utmp entry for child and send
1137 * signal to child to tell when done. Child waits for signal
1138 * before doing anything important.
1144 utmp_sig_reset(); /* reset handler to default */
1146 * Create utmp entry for child
1148 wtmp
.ut_time
= time(NULL
);
1149 wtmp
.ut_type
= LOGIN_PROCESS
;
1151 strncpy(wtmp
.ut_user
, "LOGIN", sizeof(wtmp
.ut_user
));
1152 strncpy(wtmp
.ut_host
, utmp_host
, sizeof(wtmp
.ut_host
));
1153 strncpy(wtmp
.ut_line
, clean_ttyname(line
), sizeof(wtmp
.ut_line
));
1154 #ifdef HAVE_STRUCT_UTMP_UT_ID
1155 strncpy(wtmp
.ut_id
, wtmp
.ut_line
+ 3, sizeof(wtmp
.ut_id
));
1160 if ((i
= open(wtmpf
, O_WRONLY
|O_APPEND
)) >= 0) {
1161 write(i
, &wtmp
, sizeof(struct utmp
));
1165 signal(WJSIGNAL
, sigjob
);
1167 utmp_sig_notify(pid
);
1168 # endif /* PARENT_DOES_UTMP */
1172 /* if we authenticated via K5, try and join the PAG */
1175 start_login(host
, autologin
, autoname
);
1181 extern char **environ
;
1189 if ((*envp
= getenv("TZ")))
1191 #if defined(_CRAY) || defined(__hpux)
1193 *envp
++ = "TZ=GMT0";
1202 * We only accept the environment variables listed below.
1208 static const char *reject
[] = {
1213 static const char *accept
[] = {
1214 "XAUTH=", "XAUTHORITY=", "DISPLAY=",
1228 for (cpp2
= cpp
= environ
; *cpp
; cpp
++) {
1231 for(p
= reject
; *p
; p
++)
1232 if(strncmp(*cpp
, *p
, strlen(*p
)) == 0) {
1239 for(p
= accept
; *p
; p
++)
1240 if(strncmp(*cpp
, *p
, strlen(*p
)) == 0)
1255 static void addarg(struct arg_val
*, const char*);
1260 * Assuming that we are now running as a child processes, this
1261 * function will turn us into the login process.
1265 start_login(const char *host
, int autologin
, char *name
)
1267 struct arg_val argv
;
1272 encrypt_output
= NULL
;
1273 decrypt_input
= NULL
;
1284 * Create utmp entry for child
1287 clean_tty
= clean_ttyname(line
);
1288 memset(&utmpx
, 0, sizeof(utmpx
));
1289 strncpy(utmpx
.ut_user
, ".telnet", sizeof(utmpx
.ut_user
));
1290 strncpy(utmpx
.ut_line
, clean_tty
, sizeof(utmpx
.ut_line
));
1291 #ifdef HAVE_STRUCT_UTMP_UT_ID
1292 strncpy(utmpx
.ut_id
, make_id(clean_tty
), sizeof(utmpx
.ut_id
));
1296 utmpx
.ut_type
= LOGIN_PROCESS
;
1298 gettimeofday (&tv
, NULL
);
1299 utmpx
.ut_tv
.tv_sec
= tv
.tv_sec
;
1300 utmpx
.ut_tv
.tv_usec
= tv
.tv_usec
;
1302 if (pututxline(&utmpx
) == NULL
)
1303 fatal(net
, "pututxline failed");
1310 * -h : pass on name of host.
1311 * WARNING: -h is accepted by login if and only if
1313 * -p : don't clobber the environment (so terminal type stays set).
1315 * -f : force this login, he has already been authenticated
1318 /* init argv structure */
1321 argv
.argv
=malloc(0); /*so we can call realloc later */
1322 addarg(&argv
, "login");
1323 addarg(&argv
, "-h");
1324 addarg(&argv
, host
);
1325 addarg(&argv
, "-p");
1329 user
= getenv("USER");
1330 #ifdef AUTHENTICATION
1331 if (auth_level
< 0 || autologin
!= AUTH_VALID
) {
1333 printf("User not authenticated. ");
1335 printf("Using one-time password\r\n");
1337 printf("Using plaintext username and password\r\n");
1340 addarg(&argv
, "-a");
1341 addarg(&argv
, "otp");
1344 syslog(LOG_INFO
, "unauthenticated access from %s (%s)",
1345 host
, user
? user
: "unknown user");
1347 if (auth_level
>= 0 && autologin
== AUTH_VALID
)
1348 addarg(&argv
, "-f");
1351 addarg(&argv
, "--");
1352 addarg(&argv
, strdup(user
));
1354 if (getenv("USER")) {
1356 * Assume that login will set the USER variable
1357 * correctly. For SysV systems, this means that
1358 * USER will no longer be set, just LOGNAME by
1359 * login. (The problem is that if the auto-login
1360 * fails, and the user then specifies a different
1361 * account name, he can get logged in with both
1362 * LOGNAME and USER in his environment, but the
1363 * USER value will be wrong.
1369 * This sleep(1) is in here so that telnetd can
1370 * finish up with the tty. There's a race condition
1371 * the login banner message gets lost...
1375 execv(new_login
, argv
.argv
);
1377 syslog(LOG_ERR
, "%s: %m", new_login
);
1378 fatalperror_errno(net
, new_login
, save_errno
);
1383 addarg(struct arg_val
*argv
, const char *val
)
1385 if(argv
->size
<= argv
->argc
+1) {
1386 argv
->argv
= realloc(argv
->argv
, sizeof(char*) * (argv
->size
+ 10));
1387 if (argv
->argv
== NULL
)
1388 fatal (net
, "realloc: out of memory");
1391 if((argv
->argv
[argv
->argc
++] = strdup(val
)) == NULL
)
1392 fatal (net
, "strdup: out of memory");
1393 argv
->argv
[argv
->argc
] = NULL
;
1400 * This is the function called by cleanup() to
1401 * remove the utmp entry for this person.
1408 struct utmpx utmpx
, *non_save_utxp
;
1409 char *clean_tty
= clean_ttyname(line
);
1412 * This updates the utmpx and utmp entries and make a wtmp/x entry
1416 memset(&utmpx
, 0, sizeof(utmpx
));
1417 strncpy(utmpx
.ut_line
, clean_tty
, sizeof(utmpx
.ut_line
));
1418 utmpx
.ut_type
= LOGIN_PROCESS
;
1419 non_save_utxp
= getutxline(&utmpx
);
1420 if (non_save_utxp
) {
1425 utxp
= malloc(sizeof(struct utmpx
));
1426 *utxp
= *non_save_utxp
;
1427 user0
= utxp
->ut_user
[0];
1428 utxp
->ut_user
[0] = '\0';
1429 utxp
->ut_type
= DEAD_PROCESS
;
1430 #ifdef HAVE_STRUCT_UTMPX_UT_EXIT
1431 #ifdef _STRUCT___EXIT_STATUS
1432 utxp
->ut_exit
.__e_termination
= 0;
1433 utxp
->ut_exit
.__e_exit
= 0;
1434 #elif defined(__osf__) /* XXX */
1435 utxp
->ut_exit
.ut_termination
= 0;
1436 utxp
->ut_exit
.ut_exit
= 0;
1438 utxp
->ut_exit
.e_termination
= 0;
1439 utxp
->ut_exit
.e_exit
= 0;
1442 gettimeofday (&tv
, NULL
);
1443 utxp
->ut_tv
.tv_sec
= tv
.tv_sec
;
1444 utxp
->ut_tv
.tv_usec
= tv
.tv_usec
;
1448 utxp
->ut_user
[0] = user0
;
1449 updwtmpx(WTMPX_FILE
, utxp
);
1450 #elif defined(WTMP_FILE)
1451 /* This is a strange system with a utmpx and a wtmp! */
1453 int f
= open(wtmpf
, O_WRONLY
|O_APPEND
);
1456 strncpy(wtmp
.ut_line
, clean_tty
, sizeof(wtmp
.ut_line
));
1457 strncpy(wtmp
.ut_name
, "", sizeof(wtmp
.ut_name
));
1458 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1459 strncpy(wtmp
.ut_host
, "", sizeof(wtmp
.ut_host
));
1461 wtmp
.ut_time
= time(NULL
);
1462 write(f
, &wtmp
, sizeof(wtmp
));
1473 #if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43
1479 struct utmp
*u
, *utmp
;
1482 char *clean_tty
= clean_ttyname(line
);
1484 f
= open(utmpf
, O_RDWR
);
1487 utmp
= (struct utmp
*)malloc((unsigned)statbf
.st_size
);
1489 syslog(LOG_ERR
, "utmp malloc failed");
1490 if (statbf
.st_size
&& utmp
) {
1491 nutmp
= read(f
, utmp
, (int)statbf
.st_size
);
1492 nutmp
/= sizeof(struct utmp
);
1494 for (u
= utmp
; u
< &utmp
[nutmp
] ; u
++) {
1495 if (strncmp(u
->ut_line
,
1497 sizeof(u
->ut_line
)) ||
1500 lseek(f
, ((long)u
)-((long)utmp
), L_SET
);
1501 strncpy(u
->ut_name
, "", sizeof(u
->ut_name
));
1502 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1503 strncpy(u
->ut_host
, "", sizeof(u
->ut_host
));
1505 u
->ut_time
= time(NULL
);
1506 write(f
, u
, sizeof(wtmp
));
1513 f
= open(wtmpf
, O_WRONLY
|O_APPEND
);
1515 strncpy(wtmp
.ut_line
, clean_tty
, sizeof(wtmp
.ut_line
));
1516 strncpy(wtmp
.ut_name
, "", sizeof(wtmp
.ut_name
));
1517 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1518 strncpy(wtmp
.ut_host
, "", sizeof(wtmp
.ut_host
));
1520 wtmp
.ut_time
= time(NULL
);
1521 write(f
, &wtmp
, sizeof(wtmp
));
1527 line
[strlen("/dev/")] = 'p';
1533 #if defined(__hpux) && !defined(HAVE_UTMPX_H)
1539 int fd
; /* for /etc/wtmp */
1541 utmp
.ut_type
= USER_PROCESS
;
1542 strncpy(utmp
.ut_line
, clean_ttyname(line
), sizeof(utmp
.ut_line
));
1544 utptr
= getutline(&utmp
);
1545 /* write it out only if it exists */
1547 utptr
->ut_type
= DEAD_PROCESS
;
1548 utptr
->ut_time
= time(NULL
);
1550 /* set wtmp entry if wtmp file exists */
1551 if ((fd
= open(wtmpf
, O_WRONLY
| O_APPEND
)) >= 0) {
1552 write(fd
, utptr
, sizeof(utmp
));
1560 line
[14] = line
[13];
1561 line
[13] = line
[12];
1575 * This is the routine to call when we are all through, to
1576 * clean up anything that needs to be cleaned up.
1579 #ifdef PARENT_DOES_UTMP
1585 static int incleanup
= 0;
1587 int child_status
; /* status of child process as returned by waitpid */
1588 int flags
= WNOHANG
|WUNTRACED
;
1591 * 1: Pick up the zombie, if we are being called
1592 * as the signal handler.
1593 * 2: If we are a nested cleanup(), return.
1594 * 3: Try to clean up TMPDIR.
1595 * 4: Fill in utmp with shutdown of process.
1596 * 5: Close down the network and pty connections.
1597 * 6: Finish up the TMPDIR cleanup, if needed.
1599 if (sig
== SIGCHLD
) {
1600 while (waitpid(-1, &child_status
, flags
) > 0)
1602 /* Check if the child process was stopped
1603 * rather than exited. We want cleanup only if
1604 * the child has died.
1606 if (WIFSTOPPED(child_status
)) {
1610 t
= sigblock(sigmask(SIGCHLD
));
1618 t
= cleantmp(&wtmp
);
1619 setutent(); /* just to make sure */
1631 #else /* PARENT_DOES_UTMP */
1636 #if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)
1640 vhangup(); /* XXX */
1646 p
= line
+ sizeof("/dev/") - 1;
1659 #endif /* PARENT_DOES_UTMP */
1661 #ifdef PARENT_DOES_UTMP
1666 * These three functions are used to coordinate the handling of
1667 * the utmp file between the server and the soon-to-be-login shell.
1668 * The server actually creates the utmp structure, the child calls
1669 * utmp_sig_wait(), until the server calls utmp_sig_notify() and
1670 * signals the future-login shell to proceed.
1672 static int caught
=0; /* NZ when signal intercepted */
1673 static void (*func
)(); /* address of previous handler */
1680 signal(SIGUSR1
, func
);
1687 * register signal handler for UTMP creation
1689 if ((int)(func
= signal(SIGUSR1
, _utmp_sig_rcv
)) == -1)
1690 fatalperror(net
, "telnetd/signal");
1696 signal(SIGUSR1
, func
); /* reset handler to default */
1700 # define sigoff() /* do nothing */
1701 # define sigon() /* do nothing */
1708 * Wait for parent to write our utmp entry.
1711 while (caught
== 0) {
1712 pause(); /* wait until we get a signal (sigon) */
1713 sigoff(); /* turn off signals while we check caught */
1715 sigon(); /* turn on signals again */
1719 utmp_sig_notify(pid
)
1725 static int gotsigjob
= 0;
1735 while ((jid
= waitjob(NULL
)) != -1) {
1740 jobend(jid
, NULL
, NULL
);
1746 * called by jobend() before calling cleantmp()
1747 * to find the correct $TMPDIR to cleanup.
1754 struct utmp
*cur
= NULL
;
1756 setutent(); /* just to make sure */
1757 while (cur
= getutent()) {
1758 if ( (cur
->ut_type
!= NULL
) && (jid
== cur
->ut_jid
) ) {
1767 * Clean up the TMPDIR that login created.
1768 * The first time this is called we pick up the info
1769 * from the utmp. If the job has already gone away,
1770 * then we'll clean up and be done. If not, then
1771 * when this is called the second time it will wait
1772 * for the signal that the job is done.
1779 static int first
= 1;
1780 int mask
, omask
, ret
;
1781 extern struct utmp
*getutid (const struct utmp
*_Id
);
1784 mask
= sigmask(WJSIGNAL
);
1787 omask
= sigblock(mask
);
1788 while (gotsigjob
== 0)
1793 setutent(); /* just to make sure */
1797 syslog(LOG_ERR
, "Can't get /etc/utmp entry to clean TMPDIR");
1801 * Nothing to clean up if the user shell was never started.
1803 if (utp
->ut_type
!= USER_PROCESS
|| utp
->ut_jid
== 0)
1807 * Block the WJSIGNAL while we are in jobend().
1809 omask
= sigblock(mask
);
1810 ret
= jobend(utp
->ut_jid
, utp
->ut_tpath
, utp
->ut_user
);
1816 jobend(jid
, path
, user
)
1821 static int saved_jid
= 0;
1822 static int pty_saved_jid
= 0;
1823 static char saved_path
[sizeof(wtmp
.ut_tpath
)+1];
1824 static char saved_user
[sizeof(wtmp
.ut_user
)+1];
1827 * this little piece of code comes into play
1828 * only when ptyreconnect is used to reconnect
1829 * to an previous session.
1831 * this is the only time when the
1832 * "saved_jid != jid" code is executed.
1835 if ( saved_jid
&& saved_jid
!= jid
) {
1836 if (!path
) { /* called from signal handler */
1837 pty_saved_jid
= jid
;
1839 pty_saved_jid
= saved_jid
;
1844 strlcpy(saved_path
, path
, sizeof(saved_path
));
1845 strlcpy(saved_user
, user
, sizeof(saved_user
));
1847 if (saved_jid
== 0) {
1852 /* if the jid has changed, get the correct entry from the utmp file */
1854 if ( saved_jid
!= jid
) {
1855 struct utmp
*utp
= NULL
;
1856 struct utmp
*jid_getutid();
1858 utp
= jid_getutid(pty_saved_jid
);
1861 syslog(LOG_ERR
, "Can't get /etc/utmp entry to clean TMPDIR");
1865 cleantmpdir(jid
, utp
->ut_tpath
, utp
->ut_user
);
1869 cleantmpdir(jid
, saved_path
, saved_user
);
1874 * Fork a child process to clean up the TMPDIR
1876 cleantmpdir(jid
, tpath
, user
)
1883 syslog(LOG_ERR
, "TMPDIR cleanup(%s): fork() failed: %m\n",
1887 execl(CLEANTMPCMD
, CLEANTMPCMD
, user
, tpath
, NULL
);
1888 syslog(LOG_ERR
, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1889 tpath
, CLEANTMPCMD
);
1893 * Forget about child. We will exit, and
1894 * /etc/init will pick it up.
1900 #endif /* defined(PARENT_DOES_UTMP) */