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
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 */
105 #ifdef HAVE_SYS_STREAM_H
106 #ifdef HAVE_SYS_UIO_H
112 #include <sys/stream.h>
114 #if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY)
134 #ifdef HAVE_TERMIOS_H
148 # define TCSANOW TCSETS
149 # define TCSADRAIN TCSETSW
150 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
153 # define TCSANOW TCSETA
154 # define TCSADRAIN TCSETAW
155 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
157 # define TCSANOW TIOCSETA
158 # define TCSADRAIN TIOCSETAW
159 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
162 # define tcsetattr(f, a, t) ioctl(f, a, t)
163 # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
164 (tp)->c_cflag |= (val)
165 # define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
167 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
168 (tp)->c_cflag |= ((val)<<IBSHIFT)
169 # define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
171 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
172 (tp)->c_cflag |= (val)
173 # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
175 # endif /* TCSANOW */
176 struct termios termbuf
, termbuf2
; /* pty control structure */
178 static int ttyfd
= -1;
179 int really_stream
= 0;
182 const char *new_login
= _PATH_LOGIN
;
189 * These three routines are used to get and set the "termbuf" structure
190 * to and from the kernel. init_termbuf() gets the current settings.
191 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
192 * set_termbuf() writes the structure into the kernel.
200 tcgetattr(ttyfd
, &termbuf
);
203 tcgetattr(ourpty
, &termbuf
);
211 * Only make the necessary changes.
213 if (memcmp(&termbuf
, &termbuf2
, sizeof(termbuf
)))
216 tcsetattr(ttyfd
, TCSANOW
, &termbuf
);
219 tcsetattr(ourpty
, TCSANOW
, &termbuf
);
224 * spcset(func, valp, valpp)
226 * This function takes various special characters (func), and
227 * sets *valp to the current value of that character, and
228 * *valpp to point to where in the "termbuf" structure that
231 * It returns the SLC_ level of support for this function.
236 spcset(int func
, cc_t
*valp
, cc_t
**valpp
)
239 #define setval(a, b) *valp = termbuf.c_cc[a]; \
240 *valpp = &termbuf.c_cc[a]; \
242 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
246 setval(VEOF
, SLC_VARIABLE
);
248 setval(VERASE
, SLC_VARIABLE
);
250 setval(VKILL
, SLC_VARIABLE
);
252 setval(VINTR
, SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
254 setval(VQUIT
, SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
257 setval(VSTART
, SLC_VARIABLE
);
263 setval(VSTOP
, SLC_VARIABLE
);
269 setval(VWERASE
, SLC_VARIABLE
);
275 setval(VREPRINT
, SLC_VARIABLE
);
281 setval(VLNEXT
, SLC_VARIABLE
);
286 #if !defined(VDISCARD) && defined(VFLUSHO)
287 # define VDISCARD VFLUSHO
290 setval(VDISCARD
, SLC_VARIABLE
|SLC_FLUSHOUT
);
296 setval(VSUSP
, SLC_VARIABLE
|SLC_FLUSHIN
);
302 setval(VEOL
, SLC_VARIABLE
);
306 setval(VEOL2
, SLC_VARIABLE
);
310 setval(VSTATUS
, SLC_VARIABLE
);
323 return(SLC_NOSUPPORT
);
331 * Return the number of pty's configured into the system.
339 if ((numptys
= sysconf(_SC_CRAY_NPTY
)) != -1)
342 #endif /* _SC_CRAY_NPTY */
350 * Allocate a pty. As a side effect, the external character
351 * array "line" contains the name of the slave side.
353 * Returns the file descriptor of the opened pty.
356 static char Xline
[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
360 char myline
[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
363 #if !defined(HAVE_PTSNAME) && defined(STREAMSPTY)
364 static char *ptsname(int fd
)
374 int getpty(int *ptynum
)
376 #ifdef __osf__ /* XXX */
379 if(openpty(&master
, &slave
, line
, 0, 0) == 0){
388 p
= _getpty(&master
, O_RDWR
, 0600, 1);
391 strcpy_truncate(line
, p
, sizeof(Xline
));
401 #if 0 /* && defined(HAVE_OPENPTY) */
404 if(openpty(&master
, &slave
, line
, 0, 0) == 0){
410 char *clone
[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm",
411 "/dev/ptym/clone", 0 };
414 for(q
=clone
; *q
; q
++){
423 strcpy_truncate(line
, ptsname(p
), sizeof(Xline
));
428 #endif /* STREAMSPTY */
432 snprintf(line
, sizeof(Xline
), "/dev/ptyXX");
436 snprintf(line
, sizeof(Xline
), "/dev/ptym/ptyXX");
442 for (cp
= "pqrstuvwxyzPQRST"; *cp
; cp
++) {
448 * This stat() check is just to keep us from
449 * looping through all 256 combinations if there
450 * aren't that many ptys available.
452 if (stat(line
, &stb
) < 0)
454 for (i
= 0; i
< 16; i
++) {
455 *p2
= "0123456789abcdef"[i
];
456 p
= open(line
, O_RDWR
);
461 for (p1
= &line
[8]; *p1
; p1
++)
468 if (ioctl(p
, TIOCGPGRP
, &dummy
) == 0
474 #endif /* SunOS == 4 */
480 extern lowpty
, highpty
;
483 for (*ptynum
= lowpty
; *ptynum
<= highpty
; (*ptynum
)++) {
484 snprintf(myline
, sizeof(myline
), "/dev/pty/%03d", *ptynum
);
488 snprintf(line
, sizeof(Xline
), "/dev/ttyp%03d", *ptynum
);
490 * Here are some shenanigans to make sure that there
491 * are no listeners lurking on the line.
493 if(stat(line
, &sb
) < 0) {
497 if(sb
.st_uid
|| sb
.st_gid
|| sb
.st_mode
!= 0600) {
506 * Now it should be safe...check for accessability.
508 if (access(line
, 6) == 0)
511 /* no tty side to pty so skip it */
516 #endif /* STREAMSPTY */
526 return (termbuf
.c_lflag
& ECHO
);
532 return((termbuf
.c_iflag
& IXON
) ? 1 : 0);
538 return((termbuf
.c_iflag
& IXANY
) ? 1 : 0);
545 termbuf
.c_lflag
|= ECHO
;
547 termbuf
.c_lflag
&= ~ECHO
;
553 return(!(termbuf
.c_lflag
& ICANON
));
560 termbuf
.c_iflag
&= ~ISTRIP
;
562 termbuf
.c_iflag
|= ISTRIP
;
567 tty_binaryout(int on
)
570 termbuf
.c_cflag
&= ~(CSIZE
|PARENB
);
571 termbuf
.c_cflag
|= CS8
;
572 termbuf
.c_oflag
&= ~OPOST
;
574 termbuf
.c_cflag
&= ~CSIZE
;
575 termbuf
.c_cflag
|= CS7
|PARENB
;
576 termbuf
.c_oflag
|= OPOST
;
583 return(!(termbuf
.c_iflag
& ISTRIP
));
587 tty_isbinaryout(void)
589 return(!(termbuf
.c_oflag
&OPOST
));
597 return (termbuf
.c_oflag
& OXTABS
);
600 return ((termbuf
.c_oflag
& TABDLY
) == TAB3
);
605 tty_setsofttab(int on
)
609 termbuf
.c_oflag
|= OXTABS
;
612 termbuf
.c_oflag
&= ~TABDLY
;
613 termbuf
.c_oflag
|= TAB3
;
617 termbuf
.c_oflag
&= ~OXTABS
;
620 termbuf
.c_oflag
&= ~TABDLY
;
621 termbuf
.c_oflag
|= TAB0
;
630 return (!(termbuf
.c_lflag
& ECHOCTL
));
633 return (!(termbuf
.c_lflag
& TCTLECH
));
635 # if !defined(ECHOCTL) && !defined(TCTLECH)
636 return (0); /* assumes ctl chars are echoed '^x' */
641 tty_setlitecho(int on
)
645 termbuf
.c_lflag
&= ~ECHOCTL
;
647 termbuf
.c_lflag
|= ECHOCTL
;
651 termbuf
.c_lflag
&= ~TCTLECH
;
653 termbuf
.c_lflag
|= TCTLECH
;
660 return (termbuf
.c_iflag
& ICRNL
);
664 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
673 * A table of available terminal speeds
679 { 0, B0
}, { 50, B50
}, { 75, B75
},
680 { 110, B110
}, { 134, B134
}, { 150, B150
},
681 { 200, B200
}, { 300, B300
}, { 600, B600
},
682 { 1200, B1200
}, { 1800, B1800
}, { 2400, B2400
},
711 #endif /* DECODE_BUAD */
717 struct termspeeds
*tp
;
719 for (tp
= termspeeds
; (tp
->speed
!= -1) && (val
> tp
->speed
); tp
++)
721 if (tp
->speed
== -1) /* back up to last valid value */
723 cfsetospeed(&termbuf
, tp
->value
);
724 #else /* DECODE_BUAD */
725 cfsetospeed(&termbuf
, val
);
726 #endif /* DECODE_BUAD */
733 struct termspeeds
*tp
;
735 for (tp
= termspeeds
; (tp
->speed
!= -1) && (val
> tp
->speed
); tp
++)
737 if (tp
->speed
== -1) /* back up to last valid value */
739 cfsetispeed(&termbuf
, tp
->value
);
740 #else /* DECODE_BAUD */
741 cfsetispeed(&termbuf
, val
);
742 #endif /* DECODE_BAUD */
745 #ifdef PARENT_DOES_UTMP
746 extern struct utmp wtmp
;
749 extern void utmp_sig_init (void);
750 extern void utmp_sig_reset (void);
751 extern void utmp_sig_wait (void);
752 extern void utmp_sig_notify (int);
753 # endif /* PARENT_DOES_UTMP */
757 /* I_FIND seems to live a life of its own */
758 static int my_find(int fd
, char *module
)
760 #if defined(I_FIND) && defined(I_LIST)
762 static struct str_list sl
;
767 n
= ioctl(fd
, I_LIST
, 0);
769 perror("ioctl(fd, I_LIST, 0)");
772 sl
.sl_modlist
=(struct str_mlist
*)malloc(n
* sizeof(struct str_mlist
));
774 n
= ioctl(fd
, I_LIST
, &sl
);
776 perror("ioctl(fd, I_LIST, n)");
782 for(i
=0; i
<sl
.sl_nmods
; i
++)
783 if(!strcmp(sl
.sl_modlist
[i
].l_name
, module
))
789 static void maybe_push_modules(int fd
, char **modules
)
794 for(p
=modules
; *p
; p
++){
795 err
= my_find(fd
, *p
);
798 if(err
< 0 && errno
!= EINVAL
)
799 fatalperror(net
, "my_find()");
800 /* module not pushed or does not exist */
802 /* p points to null or to an already pushed module, now push all
803 modules before this one */
805 for(p
--; p
>= modules
; p
--){
806 err
= ioctl(fd
, I_PUSH
, *p
);
807 if(err
< 0 && errno
!= EINVAL
)
808 fatalperror(net
, "I_PUSH");
816 * Open the slave side of the pty, and do any initialization
817 * that is necessary. The return value is a file descriptor
818 * for the slave side.
820 void getptyslave(void)
825 extern int def_row
, def_col
;
826 extern int def_tspeed
, def_rspeed
;
828 * Opening the slave side may cause initilization of the
829 * kernel tty structure. We need remember the state of
830 * if linemode was turned on
831 * terminal window size
833 * so that we can re-set them if we need to.
838 * Make sure that we don't have a controlling tty, and
839 * that we are the session (process group) leader.
844 fatalperror(net
, "setsid()");
847 t
= open(_PATH_TTY
, O_RDWR
);
849 ioctl(t
, TIOCNOTTY
, (char *)0);
855 # ifdef PARENT_DOES_UTMP
857 * Wait for our parent to get the utmp stuff to get done.
864 fatalperror(net
, line
);
871 * Not all systems have (or need) modules ttcompat and pckt so
872 * don't flag it as a fatal error if they don't exist.
877 /* these are the streams modules that we want pushed. note
878 that they are in reverse order, ptem will be pushed
879 first. maybe_push_modules() will try to push all modules
880 before the first one that isn't already pushed. i.e if
881 ldterm is pushed, only ttcompat will be attempted.
883 all this is because we don't know which modules are
884 available, and we don't know which modules are already
885 pushed (via autopush, for instance).
889 char *ttymodules
[] = { "ttcompat", "ldterm", "ptem", NULL
};
890 char *ptymodules
[] = { "pckt", NULL
};
892 maybe_push_modules(t
, ttymodules
);
893 maybe_push_modules(ourpty
, ptymodules
);
897 * set up the tty modes as we like them to be.
901 if (def_row
|| def_col
) {
902 memset(&ws
, 0, sizeof(ws
));
905 ioctl(t
, TIOCSWINSZ
, (char *)&ws
);
910 * Settings for sgtty based systems
914 * Settings for UNICOS (and HPUX)
916 # if defined(_CRAY) || defined(__hpux)
917 termbuf
.c_oflag
= OPOST
|ONLCR
|TAB3
;
918 termbuf
.c_iflag
= IGNPAR
|ISTRIP
|ICRNL
|IXON
;
919 termbuf
.c_lflag
= ISIG
|ICANON
|ECHO
|ECHOE
|ECHOK
;
920 termbuf
.c_cflag
= EXTB
|HUPCL
|CS8
;
924 * Settings for all other termios/termio based
925 * systems, other than 4.4BSD. In 4.4BSD the
926 * kernel does the initial terminal setup.
928 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43)
932 termbuf
.c_lflag
|= ECHO
;
933 termbuf
.c_oflag
|= ONLCR
|OXTABS
;
934 termbuf
.c_iflag
|= ICRNL
;
935 termbuf
.c_iflag
&= ~IXOFF
;
937 tty_rspeed((def_rspeed
> 0) ? def_rspeed
: 9600);
938 tty_tspeed((def_tspeed
> 0) ? def_tspeed
: 9600);
941 * Set the tty modes, and make this our controlling tty.
944 if (login_tty(t
) == -1)
945 fatalperror(net
, "login_tty");
958 * Open the specified slave side of the pty,
959 * making sure that we have a clean tty.
962 int cleanopen(char *line
)
971 * Make sure that other people can't open the
972 * slave side of the connection.
982 t
= open(line
, O_RDWR
|O_NOCTTY
);
988 * Hangup anybody else using this ttyp, then reopen it for
991 # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
992 signal(SIGHUP
, SIG_IGN
);
997 signal(SIGHUP
, SIG_DFL
);
998 t
= open(line
, O_RDWR
|O_NOCTTY
);
1002 # if defined(_CRAY) && defined(TCVHUP)
1005 signal(SIGHUP
, SIG_IGN
);
1006 ioctl(t
, TCVHUP
, (char *)0);
1007 signal(SIGHUP
, SIG_DFL
);
1009 i
= open(line
, O_RDWR
);
1016 # endif /* defined(CRAY) && defined(TCVHUP) */
1020 #if !defined(BSD4_4)
1022 int login_tty(int t
)
1024 # if defined(TIOCSCTTY) && !defined(__hpux)
1025 if (ioctl(t
, TIOCSCTTY
, (char *)0) < 0)
1026 fatalperror(net
, "ioctl(sctty)");
1029 * Close the hard fd to /dev/ttypXXX, and re-open through
1030 * the indirect /dev/tty interface.
1033 if ((t
= open("/dev/tty", O_RDWR
)) < 0)
1034 fatalperror(net
, "open(/dev/tty)");
1038 * We get our controlling tty assigned as a side-effect
1039 * of opening up a tty device. But on BSD based systems,
1040 * this only happens if our process group is zero. The
1041 * setsid() call above may have set our pgrp, so clear
1042 * it out before opening the tty...
1047 setpgrp(0, 0); /* if setpgid isn't available, setpgrp
1048 probably takes arguments */
1050 close(open(line
, O_RDWR
));
1062 #endif /* BSD <= 43 */
1065 * This comes from ../../bsd/tty.c and should not really be here.
1069 * Clean the tty name. Return a pointer to the cleaned version.
1073 clean_ttyname (char *tty
)
1077 if (strncmp (res
, _PATH_DEV
, strlen(_PATH_DEV
)) == 0)
1078 res
+= strlen(_PATH_DEV
);
1079 if (strncmp (res
, "pty/", 4) == 0)
1081 if (strncmp (res
, "ptym/", 5) == 0)
1087 * Generate a name usable as an `ut_id', typically without `tty'.
1090 #ifdef HAVE_STRUCT_UTMP_UT_ID
1096 if (strncmp (res
, "pts/", 4) == 0)
1098 if (strncmp (res
, "tty", 3) == 0)
1107 * Given a hostname, do whatever
1108 * is necessary to startup the login process on the slave side of the pty.
1113 startslave(char *host
, int autologin
, char *autoname
)
1117 #ifdef AUTHENTICATION
1118 if (!autoname
|| !autoname
[0])
1121 if (autologin
< auth_level
) {
1122 fatal(net
, "Authorization failed");
1129 "\r\n*** Connection not encrypted! "
1130 "Communication may be eavesdropped. ***\r\n";
1132 if (!no_warn
&& (encrypt_output
== 0 || decrypt_input
== 0))
1134 writenet((unsigned char*)tbuf
, strlen(tbuf
));
1136 # ifdef PARENT_DOES_UTMP
1138 # endif /* PARENT_DOES_UTMP */
1140 if ((i
= fork()) < 0)
1141 fatalperror(net
, "fork");
1143 # ifdef PARENT_DOES_UTMP
1145 * Cray parent will create utmp entry for child and send
1146 * signal to child to tell when done. Child waits for signal
1147 * before doing anything important.
1153 utmp_sig_reset(); /* reset handler to default */
1155 * Create utmp entry for child
1157 time(&wtmp
.ut_time
);
1158 wtmp
.ut_type
= LOGIN_PROCESS
;
1160 strncpy(wtmp
.ut_user
, "LOGIN", sizeof(wtmp
.ut_user
));
1161 strncpy(wtmp
.ut_host
, host
, sizeof(wtmp
.ut_host
));
1162 strncpy(wtmp
.ut_line
, clean_ttyname(line
), sizeof(wtmp
.ut_line
));
1163 #ifdef HAVE_STRUCT_UTMP_UT_ID
1164 strncpy(wtmp
.ut_id
, wtmp
.ut_line
+ 3, sizeof(wtmp
.ut_id
));
1169 if ((i
= open(wtmpf
, O_WRONLY
|O_APPEND
)) >= 0) {
1170 write(i
, &wtmp
, sizeof(struct utmp
));
1174 signal(WJSIGNAL
, sigjob
);
1176 utmp_sig_notify(pid
);
1177 # endif /* PARENT_DOES_UTMP */
1180 start_login(host
, autologin
, autoname
);
1186 extern char **environ
;
1191 extern char *getenv(const char *);
1195 if ((*envp
= getenv("TZ")))
1197 #if defined(_CRAY) || defined(__hpux)
1199 *envp
++ = "TZ=GMT0";
1208 * Remove variables from the environment that might cause login to
1209 * behave in a bad manner. To avoid this, login should be staticly
1213 static void scrub_env(void)
1215 static char *remove
[] = { "LD_", "_RLD_", "LIBPATH=", "IFS=", NULL
};
1220 for (cpp2
= cpp
= environ
; *cpp
; cpp
++) {
1221 for(p
= remove
; *p
; p
++)
1222 if(strncmp(*cpp
, *p
, strlen(*p
)) == 0)
1237 static int addarg(struct arg_val
*, char*);
1242 * Assuming that we are now running as a child processes, this
1243 * function will turn us into the login process.
1247 start_login(char *host
, int autologin
, char *name
)
1249 struct arg_val argv
;
1258 * Create utmp entry for child
1261 clean_tty
= clean_ttyname(line
);
1262 memset(&utmpx
, 0, sizeof(utmpx
));
1263 strncpy(utmpx
.ut_user
, ".telnet", sizeof(utmpx
.ut_user
));
1264 strncpy(utmpx
.ut_line
, clean_tty
, sizeof(utmpx
.ut_line
));
1265 #ifdef HAVE_STRUCT_UTMP_UT_ID
1266 strncpy(utmpx
.ut_id
, make_id(clean_tty
), sizeof(utmpx
.ut_id
));
1270 utmpx
.ut_type
= LOGIN_PROCESS
;
1272 gettimeofday (&utmpx
.ut_tv
, NULL
);
1273 if (pututxline(&utmpx
) == NULL
)
1274 fatal(net
, "pututxline failed");
1280 * -h : pass on name of host.
1281 * WARNING: -h is accepted by login if and only if
1283 * -p : don't clobber the environment (so terminal type stays set).
1285 * -f : force this login, he has already been authenticated
1288 /* init argv structure */
1291 argv
.argv
=(char**)malloc(0); /*so we can call realloc later */
1292 addarg(&argv
, "login");
1293 addarg(&argv
, "-h");
1294 addarg(&argv
, host
);
1295 addarg(&argv
, "-p");
1299 user
= getenv("USER");
1300 #ifdef AUTHENTICATION
1301 if (auth_level
< 0 || autologin
!= AUTH_VALID
) {
1303 printf("User not authenticated. "
1304 "Using plaintext username and password\r\n");
1306 addarg(&argv
, "-a");
1307 addarg(&argv
, "otp");
1310 syslog(LOG_INFO
, "unauthenticated access from %s (%s)",
1311 host
, user
? user
: "unknown user");
1313 if (auth_level
>= 0 && autologin
== AUTH_VALID
)
1314 addarg(&argv
, "-f");
1317 addarg(&argv
, "--");
1318 addarg(&argv
, strdup(user
));
1320 if (getenv("USER")) {
1322 * Assume that login will set the USER variable
1323 * correctly. For SysV systems, this means that
1324 * USER will no longer be set, just LOGNAME by
1325 * login. (The problem is that if the auto-login
1326 * fails, and the user then specifies a different
1327 * account name, he can get logged in with both
1328 * LOGNAME and USER in his environment, but the
1329 * USER value will be wrong.
1335 * This sleep(1) is in here so that telnetd can
1336 * finish up with the tty. There's a race condition
1337 * the login banner message gets lost...
1341 execv(new_login
, argv
.argv
);
1343 syslog(LOG_ERR
, "%s: %m\n", new_login
);
1344 fatalperror(net
, new_login
);
1350 static int addarg(struct arg_val
*argv
, char *val
)
1352 if(argv
->size
<= argv
->argc
+1){
1353 argv
->argv
= (char**)realloc(argv
->argv
, sizeof(char*) * (argv
->size
+ 10));
1354 if(argv
->argv
== NULL
)
1355 return 1; /* this should probably be handled better */
1358 argv
->argv
[argv
->argc
++]=val
;
1359 argv
->argv
[argv
->argc
]=NULL
;
1367 * This is the function called by cleanup() to
1368 * remove the utmp entry for this person.
1375 struct utmpx
*utxp
, utmpx
;
1376 char *clean_tty
= clean_ttyname(line
);
1379 * This updates the utmpx and utmp entries and make a wtmp/x entry
1383 memset(&utmpx
, 0, sizeof(utmpx
));
1384 strncpy(utmpx
.ut_line
, clean_tty
, sizeof(utmpx
.ut_line
));
1385 utmpx
.ut_type
= LOGIN_PROCESS
;
1386 utxp
= getutxline(&utmpx
);
1388 utxp
->ut_user
[0] = '\0';
1389 utxp
->ut_type
= DEAD_PROCESS
;
1390 #ifdef HAVE_STRUCT_UTMPX_UT_EXIT
1391 #ifdef _STRUCT___EXIT_STATUS
1392 utxp
->ut_exit
.__e_termination
= 0;
1393 utxp
->ut_exit
.__e_exit
= 0;
1394 #elif defined(__osf__) /* XXX */
1395 utxp
->ut_exit
.ut_termination
= 0;
1396 utxp
->ut_exit
.ut_exit
= 0;
1398 utxp
->ut_exit
.e_termination
= 0;
1399 utxp
->ut_exit
.e_exit
= 0;
1402 gettimeofday(&utxp
->ut_tv
, NULL
);
1405 updwtmpx(WTMPX_FILE
, utxp
);
1406 #elif defined(WTMP_FILE)
1407 /* This is a strange system with a utmpx and a wtmp! */
1409 int f
= open(wtmpf
, O_WRONLY
|O_APPEND
);
1412 strncpy(wtmp
.ut_line
, clean_tty
, sizeof(wtmp
.ut_line
));
1413 strncpy(wtmp
.ut_name
, "", sizeof(wtmp
.ut_name
));
1414 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1415 strncpy(wtmp
.ut_host
, "", sizeof(wtmp
.ut_host
));
1417 time(&wtmp
.ut_time
);
1418 write(f
, &wtmp
, sizeof(wtmp
));
1430 #if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43
1436 struct utmp
*u
, *utmp
;
1439 char *clean_tty
= clean_ttyname(line
);
1441 f
= open(utmpf
, O_RDWR
);
1444 utmp
= (struct utmp
*)malloc((unsigned)statbf
.st_size
);
1446 syslog(LOG_ERR
, "utmp malloc failed");
1447 if (statbf
.st_size
&& utmp
) {
1448 nutmp
= read(f
, utmp
, (int)statbf
.st_size
);
1449 nutmp
/= sizeof(struct utmp
);
1451 for (u
= utmp
; u
< &utmp
[nutmp
] ; u
++) {
1452 if (strncmp(u
->ut_line
,
1454 sizeof(u
->ut_line
)) ||
1457 lseek(f
, ((long)u
)-((long)utmp
), L_SET
);
1458 strncpy(u
->ut_name
, "", sizeof(u
->ut_name
));
1459 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1460 strncpy(u
->ut_host
, "", sizeof(u
->ut_host
));
1463 write(f
, u
, sizeof(wtmp
));
1470 f
= open(wtmpf
, O_WRONLY
|O_APPEND
);
1472 strncpy(wtmp
.ut_line
, clean_tty
, sizeof(wtmp
.ut_line
));
1473 strncpy(wtmp
.ut_name
, "", sizeof(wtmp
.ut_name
));
1474 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1475 strncpy(wtmp
.ut_host
, "", sizeof(wtmp
.ut_host
));
1477 time(&wtmp
.ut_time
);
1478 write(f
, &wtmp
, sizeof(wtmp
));
1484 line
[strlen("/dev/")] = 'p';
1490 #if defined(__hpux) && !defined(HAVE_UTMPX_H)
1496 int fd
; /* for /etc/wtmp */
1498 utmp
.ut_type
= USER_PROCESS
;
1499 strncpy(utmp
.ut_line
, clean_ttyname(line
), sizeof(utmp
.ut_line
));
1501 utptr
= getutline(&utmp
);
1502 /* write it out only if it exists */
1504 utptr
->ut_type
= DEAD_PROCESS
;
1505 utptr
->ut_time
= time(NULL
);
1507 /* set wtmp entry if wtmp file exists */
1508 if ((fd
= open(wtmpf
, O_WRONLY
| O_APPEND
)) >= 0) {
1509 write(fd
, utptr
, sizeof(utmp
));
1517 line
[14] = line
[13];
1518 line
[13] = line
[12];
1532 * This is the routine to call when we are all through, to
1533 * clean up anything that needs to be cleaned up.
1536 #ifdef PARENT_DOES_UTMP
1542 static int incleanup
= 0;
1544 int child_status
; /* status of child process as returned by waitpid */
1545 int flags
= WNOHANG
|WUNTRACED
;
1548 * 1: Pick up the zombie, if we are being called
1549 * as the signal handler.
1550 * 2: If we are a nested cleanup(), return.
1551 * 3: Try to clean up TMPDIR.
1552 * 4: Fill in utmp with shutdown of process.
1553 * 5: Close down the network and pty connections.
1554 * 6: Finish up the TMPDIR cleanup, if needed.
1556 if (sig
== SIGCHLD
) {
1557 while (waitpid(-1, &child_status
, flags
) > 0)
1559 /* Check if the child process was stopped
1560 * rather than exited. We want cleanup only if
1561 * the child has died.
1563 if (WIFSTOPPED(child_status
)) {
1567 t
= sigblock(sigmask(SIGCHLD
));
1575 t
= cleantmp(&wtmp
);
1576 setutent(); /* just to make sure */
1588 #else /* PARENT_DOES_UTMP */
1593 #if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)
1597 vhangup(); /* XXX */
1603 p
= line
+ sizeof("/dev/") - 1;
1616 #endif /* PARENT_DOES_UTMP */
1618 #ifdef PARENT_DOES_UTMP
1623 * These three functions are used to coordinate the handling of
1624 * the utmp file between the server and the soon-to-be-login shell.
1625 * The server actually creates the utmp structure, the child calls
1626 * utmp_sig_wait(), until the server calls utmp_sig_notify() and
1627 * signals the future-login shell to proceed.
1629 static int caught
=0; /* NZ when signal intercepted */
1630 static void (*func
)(); /* address of previous handler */
1637 signal(SIGUSR1
, func
);
1644 * register signal handler for UTMP creation
1646 if ((int)(func
= signal(SIGUSR1
, _utmp_sig_rcv
)) == -1)
1647 fatalperror(net
, "telnetd/signal");
1653 signal(SIGUSR1
, func
); /* reset handler to default */
1657 # define sigoff() /* do nothing */
1658 # define sigon() /* do nothing */
1665 * Wait for parent to write our utmp entry.
1668 while (caught
== 0) {
1669 pause(); /* wait until we get a signal (sigon) */
1670 sigoff(); /* turn off signals while we check caught */
1672 sigon(); /* turn on signals again */
1676 utmp_sig_notify(pid
)
1682 static int gotsigjob
= 0;
1692 while ((jid
= waitjob(NULL
)) != -1) {
1697 jobend(jid
, NULL
, NULL
);
1703 * called by jobend() before calling cleantmp()
1704 * to find the correct $TMPDIR to cleanup.
1711 struct utmp
*cur
= NULL
;
1713 setutent(); /* just to make sure */
1714 while (cur
= getutent()) {
1715 if ( (cur
->ut_type
!= NULL
) && (jid
== cur
->ut_jid
) ) {
1724 * Clean up the TMPDIR that login created.
1725 * The first time this is called we pick up the info
1726 * from the utmp. If the job has already gone away,
1727 * then we'll clean up and be done. If not, then
1728 * when this is called the second time it will wait
1729 * for the signal that the job is done.
1736 static int first
= 1;
1737 int mask
, omask
, ret
;
1738 extern struct utmp
*getutid (const struct utmp
*_Id
);
1741 mask
= sigmask(WJSIGNAL
);
1744 omask
= sigblock(mask
);
1745 while (gotsigjob
== 0)
1750 setutent(); /* just to make sure */
1754 syslog(LOG_ERR
, "Can't get /etc/utmp entry to clean TMPDIR");
1758 * Nothing to clean up if the user shell was never started.
1760 if (utp
->ut_type
!= USER_PROCESS
|| utp
->ut_jid
== 0)
1764 * Block the WJSIGNAL while we are in jobend().
1766 omask
= sigblock(mask
);
1767 ret
= jobend(utp
->ut_jid
, utp
->ut_tpath
, utp
->ut_user
);
1773 jobend(jid
, path
, user
)
1778 static int saved_jid
= 0;
1779 static int pty_saved_jid
= 0;
1780 static char saved_path
[sizeof(wtmp
.ut_tpath
)+1];
1781 static char saved_user
[sizeof(wtmp
.ut_user
)+1];
1784 * this little piece of code comes into play
1785 * only when ptyreconnect is used to reconnect
1786 * to an previous session.
1788 * this is the only time when the
1789 * "saved_jid != jid" code is executed.
1792 if ( saved_jid
&& saved_jid
!= jid
) {
1793 if (!path
) { /* called from signal handler */
1794 pty_saved_jid
= jid
;
1796 pty_saved_jid
= saved_jid
;
1801 strncpy(saved_path
, path
, sizeof(wtmp
.ut_tpath
));
1802 strncpy(saved_user
, user
, sizeof(wtmp
.ut_user
));
1803 saved_path
[sizeof(saved_path
)] = '\0';
1804 saved_user
[sizeof(saved_user
)] = '\0';
1806 if (saved_jid
== 0) {
1811 /* if the jid has changed, get the correct entry from the utmp file */
1813 if ( saved_jid
!= jid
) {
1814 struct utmp
*utp
= NULL
;
1815 struct utmp
*jid_getutid();
1817 utp
= jid_getutid(pty_saved_jid
);
1820 syslog(LOG_ERR
, "Can't get /etc/utmp entry to clean TMPDIR");
1824 cleantmpdir(jid
, utp
->ut_tpath
, utp
->ut_user
);
1828 cleantmpdir(jid
, saved_path
, saved_user
);
1833 * Fork a child process to clean up the TMPDIR
1835 cleantmpdir(jid
, tpath
, user
)
1842 syslog(LOG_ERR
, "TMPDIR cleanup(%s): fork() failed: %m\n",
1846 execl(CLEANTMPCMD
, CLEANTMPCMD
, user
, tpath
, 0);
1847 syslog(LOG_ERR
, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1848 tpath
, CLEANTMPCMD
);
1852 * Forget about child. We will exit, and
1853 * /etc/init will pick it up.
1859 #endif /* defined(PARENT_DOES_UTMP) */