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.89.2.6 2000/12/08 23:34:05 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 wtmp.ut_time = time(NULL);
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 * We only accept the environment variables listed below.
1214 static const char *reject[] = {
1219 static const char *accept[] = {
1220 "XAUTH=", "XAUTHORITY=", "DISPLAY=",
1234 for (cpp2 = cpp = environ; *cpp; cpp++) {
1237 for(p = reject; *p; p++)
1238 if(strncmp(*cpp, *p, strlen(*p)) == 0) {
1245 for(p = accept; *p; p++)
1246 if(strncmp(*cpp, *p, strlen(*p)) == 0)
1261 static int addarg(struct arg_val*, char*);
1266 * Assuming that we are now running as a child processes, this
1267 * function will turn us into the login process.
1271 start_login(char *host, int autologin, char *name)
1273 struct arg_val argv;
1282 * Create utmp entry for child
1285 clean_tty = clean_ttyname(line);
1286 memset(&utmpx, 0, sizeof(utmpx));
1287 strncpy(utmpx.ut_user, ".telnet", sizeof(utmpx.ut_user));
1288 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1289 #ifdef HAVE_STRUCT_UTMP_UT_ID
1290 strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id));
1294 utmpx.ut_type = LOGIN_PROCESS;
1296 gettimeofday (&utmpx.ut_tv, NULL);
1297 if (pututxline(&utmpx) == NULL)
1298 fatal(net, "pututxline failed");
1304 * -h : pass on name of host.
1305 * WARNING: -h is accepted by login if and only if
1307 * -p : don't clobber the environment (so terminal type stays set).
1309 * -f : force this login, he has already been authenticated
1312 /* init argv structure */
1315 argv.argv=(char**)malloc(0); /*so we can call realloc later */
1316 addarg(&argv, "login");
1317 addarg(&argv, "-h");
1318 addarg(&argv, host);
1319 addarg(&argv, "-p");
1323 user = getenv("USER");
1324 #ifdef AUTHENTICATION
1325 if (auth_level < 0 || autologin != AUTH_VALID) {
1327 printf("User not authenticated. ");
1329 printf("Using one-time password\r\n");
1331 printf("Using plaintext username and password\r\n");
1334 addarg(&argv, "-a");
1335 addarg(&argv, "otp");
1338 syslog(LOG_INFO, "unauthenticated access from %s (%s)",
1339 host, user ? user : "unknown user");
1341 if (auth_level >= 0 && autologin == AUTH_VALID)
1342 addarg(&argv, "-f");
1345 addarg(&argv, "--");
1346 addarg(&argv, strdup(user));
1348 if (getenv("USER")) {
1350 * Assume that login will set the USER variable
1351 * correctly. For SysV systems, this means that
1352 * USER will no longer be set, just LOGNAME by
1353 * login. (The problem is that if the auto-login
1354 * fails, and the user then specifies a different
1355 * account name, he can get logged in with both
1356 * LOGNAME and USER in his environment, but the
1357 * USER value will be wrong.
1363 * This sleep(1) is in here so that telnetd can
1364 * finish up with the tty. There's a race condition
1365 * the login banner message gets lost...
1369 execv(new_login, argv.argv);
1371 syslog(LOG_ERR, "%s: %m\n", new_login);
1372 fatalperror(net, new_login);
1378 static int addarg(struct arg_val *argv, char *val)
1380 if(argv->size <= argv->argc+1){
1381 argv->argv = (char**)realloc(argv->argv, sizeof(char*) * (argv->size + 10));
1382 if(argv->argv == NULL)
1383 return 1; /* this should probably be handled better */
1386 argv->argv[argv->argc++]=val;
1387 argv->argv[argv->argc]=NULL;
1395 * This is the function called by cleanup() to
1396 * remove the utmp entry for this person.
1403 struct utmpx utmpx, *non_save_utxp;
1404 char *clean_tty = clean_ttyname(line);
1407 * This updates the utmpx and utmp entries and make a wtmp/x entry
1411 memset(&utmpx, 0, sizeof(utmpx));
1412 strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1413 utmpx.ut_type = LOGIN_PROCESS;
1414 non_save_utxp = getutxline(&utmpx);
1415 if (non_save_utxp) {
1419 utxp = malloc(sizeof(struct utmpx));
1420 *utxp = *non_save_utxp;
1421 user0 = utxp->ut_user[0];
1422 utxp->ut_user[0] = '\0';
1423 utxp->ut_type = DEAD_PROCESS;
1424 #ifdef HAVE_STRUCT_UTMPX_UT_EXIT
1425 #ifdef _STRUCT___EXIT_STATUS
1426 utxp->ut_exit.__e_termination = 0;
1427 utxp->ut_exit.__e_exit = 0;
1428 #elif defined(__osf__) /* XXX */
1429 utxp->ut_exit.ut_termination = 0;
1430 utxp->ut_exit.ut_exit = 0;
1432 utxp->ut_exit.e_termination = 0;
1433 utxp->ut_exit.e_exit = 0;
1436 gettimeofday(&utxp->ut_tv, NULL);
1439 utxp->ut_user[0] = user0;
1440 updwtmpx(WTMPX_FILE, utxp);
1441 #elif defined(WTMP_FILE)
1442 /* This is a strange system with a utmpx and a wtmp! */
1444 int f = open(wtmpf, O_WRONLY|O_APPEND);
1447 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));
1448 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));
1449 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1450 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));
1452 wtmp.ut_time = time(NULL);
1453 write(f, &wtmp, sizeof(wtmp));
1464 #if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43
1470 struct utmp *u, *utmp;
1473 char *clean_tty = clean_ttyname(line);
1475 f = open(utmpf, O_RDWR);
1478 utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
1480 syslog(LOG_ERR, "utmp malloc failed");
1481 if (statbf.st_size && utmp) {
1482 nutmp = read(f, utmp, (int)statbf.st_size);
1483 nutmp /= sizeof(struct utmp);
1485 for (u = utmp ; u < &utmp[nutmp] ; u++) {
1486 if (strncmp(u->ut_line,
1488 sizeof(u->ut_line)) ||
1491 lseek(f, ((long)u)-((long)utmp), L_SET);
1492 strncpy(u->ut_name, "", sizeof(u->ut_name));
1493 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1494 strncpy(u->ut_host, "", sizeof(u->ut_host));
1496 u->ut_time = time(NULL);
1497 write(f, u, sizeof(wtmp));
1504 f = open(wtmpf, O_WRONLY|O_APPEND);
1506 strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line));
1507 strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));
1508 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1509 strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));
1511 wtmp.ut_time = time(NULL);
1512 write(f, &wtmp, sizeof(wtmp));
1518 line[strlen("/dev/")] = 'p';
1524 #if defined(__hpux) && !defined(HAVE_UTMPX_H)
1530 int fd; /* for /etc/wtmp */
1532 utmp.ut_type = USER_PROCESS;
1533 strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line));
1535 utptr = getutline(&utmp);
1536 /* write it out only if it exists */
1538 utptr->ut_type = DEAD_PROCESS;
1539 utptr->ut_time = time(NULL);
1541 /* set wtmp entry if wtmp file exists */
1542 if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
1543 write(fd, utptr, sizeof(utmp));
1551 line[14] = line[13];
1552 line[13] = line[12];
1566 * This is the routine to call when we are all through, to
1567 * clean up anything that needs to be cleaned up.
1570 #ifdef PARENT_DOES_UTMP
1576 static int incleanup = 0;
1578 int child_status; /* status of child process as returned by waitpid */
1579 int flags = WNOHANG|WUNTRACED;
1582 * 1: Pick up the zombie, if we are being called
1583 * as the signal handler.
1584 * 2: If we are a nested cleanup(), return.
1585 * 3: Try to clean up TMPDIR.
1586 * 4: Fill in utmp with shutdown of process.
1587 * 5: Close down the network and pty connections.
1588 * 6: Finish up the TMPDIR cleanup, if needed.
1590 if (sig == SIGCHLD) {
1591 while (waitpid(-1, &child_status, flags) > 0)
1593 /* Check if the child process was stopped
1594 * rather than exited. We want cleanup only if
1595 * the child has died.
1597 if (WIFSTOPPED(child_status)) {
1601 t = sigblock(sigmask(SIGCHLD));
1609 t = cleantmp(&wtmp);
1610 setutent(); /* just to make sure */
1622 #else /* PARENT_DOES_UTMP */
1627 #if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)
1631 vhangup(); /* XXX */
1637 p = line + sizeof("/dev/") - 1;
1650 #endif /* PARENT_DOES_UTMP */
1652 #ifdef PARENT_DOES_UTMP
1657 * These three functions are used to coordinate the handling of
1658 * the utmp file between the server and the soon-to-be-login shell.
1659 * The server actually creates the utmp structure, the child calls
1660 * utmp_sig_wait(), until the server calls utmp_sig_notify() and
1661 * signals the future-login shell to proceed.
1663 static int caught=0; /* NZ when signal intercepted */
1664 static void (*func)(); /* address of previous handler */
1671 signal(SIGUSR1, func);
1678 * register signal handler for UTMP creation
1680 if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1681 fatalperror(net, "telnetd/signal");
1687 signal(SIGUSR1, func); /* reset handler to default */
1691 # define sigoff() /* do nothing */
1692 # define sigon() /* do nothing */
1699 * Wait for parent to write our utmp entry.
1702 while (caught == 0) {
1703 pause(); /* wait until we get a signal (sigon) */
1704 sigoff(); /* turn off signals while we check caught */
1706 sigon(); /* turn on signals again */
1710 utmp_sig_notify(pid)
1716 static int gotsigjob = 0;
1726 while ((jid = waitjob(NULL)) != -1) {
1731 jobend(jid, NULL, NULL);
1737 * called by jobend() before calling cleantmp()
1738 * to find the correct $TMPDIR to cleanup.
1745 struct utmp *cur = NULL;
1747 setutent(); /* just to make sure */
1748 while (cur = getutent()) {
1749 if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
1758 * Clean up the TMPDIR that login created.
1759 * The first time this is called we pick up the info
1760 * from the utmp. If the job has already gone away,
1761 * then we'll clean up and be done. If not, then
1762 * when this is called the second time it will wait
1763 * for the signal that the job is done.
1770 static int first = 1;
1771 int mask, omask, ret;
1772 extern struct utmp *getutid (const struct utmp *_Id);
1775 mask = sigmask(WJSIGNAL);
1778 omask = sigblock(mask);
1779 while (gotsigjob == 0)
1784 setutent(); /* just to make sure */
1788 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1792 * Nothing to clean up if the user shell was never started.
1794 if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
1798 * Block the WJSIGNAL while we are in jobend().
1800 omask = sigblock(mask);
1801 ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
1807 jobend(jid, path, user)
1812 static int saved_jid = 0;
1813 static int pty_saved_jid = 0;
1814 static char saved_path[sizeof(wtmp.ut_tpath)+1];
1815 static char saved_user[sizeof(wtmp.ut_user)+1];
1818 * this little piece of code comes into play
1819 * only when ptyreconnect is used to reconnect
1820 * to an previous session.
1822 * this is the only time when the
1823 * "saved_jid != jid" code is executed.
1826 if ( saved_jid && saved_jid != jid ) {
1827 if (!path) { /* called from signal handler */
1828 pty_saved_jid = jid;
1830 pty_saved_jid = saved_jid;
1835 strncpy(saved_path, path, sizeof(wtmp.ut_tpath));
1836 strncpy(saved_user, user, sizeof(wtmp.ut_user));
1837 saved_path[sizeof(saved_path)] = '\0';
1838 saved_user[sizeof(saved_user)] = '\0';
1840 if (saved_jid == 0) {
1845 /* if the jid has changed, get the correct entry from the utmp file */
1847 if ( saved_jid != jid ) {
1848 struct utmp *utp = NULL;
1849 struct utmp *jid_getutid();
1851 utp = jid_getutid(pty_saved_jid);
1854 syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1858 cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
1862 cleantmpdir(jid, saved_path, saved_user);
1867 * Fork a child process to clean up the TMPDIR
1869 cleantmpdir(jid, tpath, user)
1876 syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
1880 execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0);
1881 syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1882 tpath, CLEANTMPCMD);
1886 * Forget about child. We will exit, and
1887 * /etc/init will pick it up.
1893 #endif /* defined(PARENT_DOES_UTMP) */