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.90 2000/01/01 11:53:59 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 */
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 strlcpy(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 strlcpy(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 == 40 */
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 void 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. ");
1305 printf("Using one-time password\r\n");
1307 printf("Using plaintext username and password\r\n");
1310 addarg(&argv, "-a");
1311 addarg(&argv, "otp");
1314 syslog(LOG_INFO, "unauthenticated access from %s (%s)",
1315 host, user ? user : "unknown user");
1317 if (auth_level >= 0 && autologin == AUTH_VALID)
1318 addarg(&argv, "-f");
1321 addarg(&argv, "--");
1322 addarg(&argv, strdup(user));
1324 if (getenv("USER")) {
1326 * Assume that login will set the USER variable
1327 * correctly. For SysV systems, this means that
1328 * USER will no longer be set, just LOGNAME by
1329 * login. (The problem is that if the auto-login
1330 * fails, and the user then specifies a different
1331 * account name, he can get logged in with both
1332 * LOGNAME and USER in his environment, but the
1333 * USER value will be wrong.
1339 * This sleep(1) is in here so that telnetd can
1340 * finish up with the tty. There's a race condition
1341 * the login banner message gets lost...
1345 execv(new_login, argv.argv);
1347 syslog(LOG_ERR, "%s: %m\n", new_login);
1348 fatalperror(net, new_login);
1353 addarg(struct arg_val *argv, char *val)
1355 if(argv->size <= argv->argc+1) {
1356 argv->argv = realloc(argv->argv, sizeof(char*) * (argv->size + 10));
1357 if (argv->argv == NULL)
1358 fatal (net, "realloc: out of memory");
1361 argv->argv[argv->argc++] = val;
1362 argv->argv[argv->argc] = NULL;
1369 * This is the function called by cleanup() to
1370 * remove the utmp entry for this person.
1377 struct utmpx utmpx, *non_save_utxp;
1378 char *clean_tty = clean_ttyname(line);
1381 * This updates the utmpx and utmp entries and make a wtmp/x entry
1385 memset(&utmpx, 0, sizeof(utmpx));
1386 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1387 utmpx.ut_type = LOGIN_PROCESS;
1388 non_save_utxp = getutxline(&utmpx);
1389 if (non_save_utxp) {
1393 utxp = malloc(sizeof(struct utmpx));
1394 *utxp = *non_save_utxp;
1395 user0 = utxp->ut_user[0];
1396 utxp->ut_user[0] = '\0';
1397 utxp->ut_type = DEAD_PROCESS;
1398 #ifdef HAVE_STRUCT_UTMPX_UT_EXIT
1399 #ifdef _STRUCT___EXIT_STATUS
1400 utxp->ut_exit.__e_termination = 0;
1401 utxp->ut_exit.__e_exit = 0;
1402 #elif defined(__osf__) /* XXX */
1403 utxp->ut_exit.ut_termination = 0;
1404 utxp->ut_exit.ut_exit = 0;
1406 utxp->ut_exit.e_termination = 0;
1407 utxp->ut_exit.e_exit = 0;
1410 gettimeofday(&utxp->ut_tv, NULL);
1413 utxp->ut_user[0] = user0;
1414 updwtmpx(WTMPX_FILE, utxp);
1415 #elif defined(WTMP_FILE)
1416 /* This is a strange system with a utmpx and a wtmp! */
1418 int f = open(wtmpf, O_WRONLY|O_APPEND);
1421 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));
1422 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));
1423 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1424 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));
1426 time(&wtmp.ut_time);
1427 write(f, &wtmp, sizeof(wtmp));
1438 #if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43
1444 struct utmp *u, *utmp;
1447 char *clean_tty = clean_ttyname(line);
1449 f = open(utmpf, O_RDWR);
1452 utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
1454 syslog(LOG_ERR, "utmp malloc failed");
1455 if (statbf.st_size && utmp) {
1456 nutmp = read(f, utmp, (int)statbf.st_size);
1457 nutmp /= sizeof(struct utmp);
1459 for (u = utmp ; u < &utmp[nutmp] ; u++) {
1460 if (strncmp(u->ut_line,
1462 sizeof(u->ut_line)) ||
1465 lseek(f, ((long)u)-((long)utmp), L_SET);
1466 strncpy(u->ut_name, "", sizeof(u->ut_name));
1467 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1468 strncpy(u->ut_host, "", sizeof(u->ut_host));
1471 write(f, u, sizeof(wtmp));
1478 f = open(wtmpf, O_WRONLY|O_APPEND);
1480 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));
1481 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));
1482 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1483 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));
1485 time(&wtmp.ut_time);
1486 write(f, &wtmp, sizeof(wtmp));
1492 line[strlen("/dev/")] = 'p';
1498 #if defined(__hpux) && !defined(HAVE_UTMPX_H)
1504 int fd; /* for /etc/wtmp */
1506 utmp.ut_type = USER_PROCESS;
1507 strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line));
1509 utptr = getutline(&utmp);
1510 /* write it out only if it exists */
1512 utptr->ut_type = DEAD_PROCESS;
1513 utptr->ut_time = time(NULL);
1515 /* set wtmp entry if wtmp file exists */
1516 if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
1517 write(fd, utptr, sizeof(utmp));
1525 line[14] = line[13];
1526 line[13] = line[12];
1540 * This is the routine to call when we are all through, to
1541 * clean up anything that needs to be cleaned up.
1544 #ifdef PARENT_DOES_UTMP
1550 static int incleanup = 0;
1552 int child_status; /* status of child process as returned by waitpid */
1553 int flags = WNOHANG|WUNTRACED;
1556 * 1: Pick up the zombie, if we are being called
1557 * as the signal handler.
1558 * 2: If we are a nested cleanup(), return.
1559 * 3: Try to clean up TMPDIR.
1560 * 4: Fill in utmp with shutdown of process.
1561 * 5: Close down the network and pty connections.
1562 * 6: Finish up the TMPDIR cleanup, if needed.
1564 if (sig == SIGCHLD) {
1565 while (waitpid(-1, &child_status, flags) > 0)
1567 /* Check if the child process was stopped
1568 * rather than exited. We want cleanup only if
1569 * the child has died.
1571 if (WIFSTOPPED(child_status)) {
1575 t = sigblock(sigmask(SIGCHLD));
1583 t = cleantmp(&wtmp);
1584 setutent(); /* just to make sure */
1596 #else /* PARENT_DOES_UTMP */
1601 #if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)
1605 vhangup(); /* XXX */
1611 p = line + sizeof("/dev/") - 1;
1624 #endif /* PARENT_DOES_UTMP */
1626 #ifdef PARENT_DOES_UTMP
1631 * These three functions are used to coordinate the handling of
1632 * the utmp file between the server and the soon-to-be-login shell.
1633 * The server actually creates the utmp structure, the child calls
1634 * utmp_sig_wait(), until the server calls utmp_sig_notify() and
1635 * signals the future-login shell to proceed.
1637 static int caught=0; /* NZ when signal intercepted */
1638 static void (*func)(); /* address of previous handler */
1645 signal(SIGUSR1, func);
1652 * register signal handler for UTMP creation
1654 if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1655 fatalperror(net, "telnetd/signal");
1661 signal(SIGUSR1, func); /* reset handler to default */
1665 # define sigoff() /* do nothing */
1666 # define sigon() /* do nothing */
1673 * Wait for parent to write our utmp entry.
1676 while (caught == 0) {
1677 pause(); /* wait until we get a signal (sigon) */
1678 sigoff(); /* turn off signals while we check caught */
1680 sigon(); /* turn on signals again */
1684 utmp_sig_notify(pid)
1690 static int gotsigjob = 0;
1700 while ((jid = waitjob(NULL)) != -1) {
1705 jobend(jid, NULL, NULL);
1711 * called by jobend() before calling cleantmp()
1712 * to find the correct $TMPDIR to cleanup.
1719 struct utmp *cur = NULL;
1721 setutent(); /* just to make sure */
1722 while (cur = getutent()) {
1723 if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
1732 * Clean up the TMPDIR that login created.
1733 * The first time this is called we pick up the info
1734 * from the utmp. If the job has already gone away,
1735 * then we'll clean up and be done. If not, then
1736 * when this is called the second time it will wait
1737 * for the signal that the job is done.
1744 static int first = 1;
1745 int mask, omask, ret;
1746 extern struct utmp *getutid (const struct utmp *_Id);
1749 mask = sigmask(WJSIGNAL);
1752 omask = sigblock(mask);
1753 while (gotsigjob == 0)
1758 setutent(); /* just to make sure */
1762 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1766 * Nothing to clean up if the user shell was never started.
1768 if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
1772 * Block the WJSIGNAL while we are in jobend().
1774 omask = sigblock(mask);
1775 ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
1781 jobend(jid, path, user)
1786 static int saved_jid = 0;
1787 static int pty_saved_jid = 0;
1788 static char saved_path[sizeof(wtmp.ut_tpath)+1];
1789 static char saved_user[sizeof(wtmp.ut_user)+1];
1792 * this little piece of code comes into play
1793 * only when ptyreconnect is used to reconnect
1794 * to an previous session.
1796 * this is the only time when the
1797 * "saved_jid != jid" code is executed.
1800 if ( saved_jid && saved_jid != jid ) {
1801 if (!path) { /* called from signal handler */
1802 pty_saved_jid = jid;
1804 pty_saved_jid = saved_jid;
1809 strncpy(saved_path, path, sizeof(wtmp.ut_tpath));
1810 strncpy(saved_user, user, sizeof(wtmp.ut_user));
1811 saved_path[sizeof(saved_path)] = '\0';
1812 saved_user[sizeof(saved_user)] = '\0';
1814 if (saved_jid == 0) {
1819 /* if the jid has changed, get the correct entry from the utmp file */
1821 if ( saved_jid != jid ) {
1822 struct utmp *utp = NULL;
1823 struct utmp *jid_getutid();
1825 utp = jid_getutid(pty_saved_jid);
1828 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1832 cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
1836 cleantmpdir(jid, saved_path, saved_user);
1841 * Fork a child process to clean up the TMPDIR
1843 cleantmpdir(jid, tpath, user)
1850 syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
1854 execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0);
1855 syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1856 tpath, CLEANTMPCMD);
1860 * Forget about child. We will exit, and
1861 * /etc/init will pick it up.
1867 #endif /* defined(PARENT_DOES_UTMP) */