157416Smarkm/* 257416Smarkm * Copyright (c) 1989, 1993 357416Smarkm * The Regents of the University of California. All rights reserved. 457416Smarkm * 557416Smarkm * Redistribution and use in source and binary forms, with or without 657416Smarkm * modification, are permitted provided that the following conditions 757416Smarkm * are met: 857416Smarkm * 1. Redistributions of source code must retain the above copyright 957416Smarkm * notice, this list of conditions and the following disclaimer. 1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1157416Smarkm * notice, this list of conditions and the following disclaimer in the 1257416Smarkm * documentation and/or other materials provided with the distribution. 1357416Smarkm * 3. All advertising materials mentioning features or use of this software 1457416Smarkm * must display the following acknowledgement: 1557416Smarkm * This product includes software developed by the University of 1657416Smarkm * California, Berkeley and its contributors. 1757416Smarkm * 4. Neither the name of the University nor the names of its contributors 1857416Smarkm * may be used to endorse or promote products derived from this software 1957416Smarkm * without specific prior written permission. 2057416Smarkm * 2157416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2257416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2357416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2457416Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2557416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2657416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2757416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2857416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2957416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3057416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3157416Smarkm * SUCH DAMAGE. 3257416Smarkm */ 3357416Smarkm 3457416Smarkm#include "telnetd.h" 3557416Smarkm 36233294SstasRCSID("$Id$"); 3757416Smarkm 3857416Smarkm#ifdef _SC_CRAY_SECURE_SYS 3957416Smarkm#include <sys/sysv.h> 4057416Smarkm#include <sys/secdev.h> 4157416Smarkm#include <sys/secparm.h> 4257416Smarkm#include <sys/usrv.h> 4357416Smarkmint secflag; 4457416Smarkmchar tty_dev[16]; 4557416Smarkmstruct secdev dv; 4657416Smarkmstruct sysv sysv; 4757416Smarkmstruct socksec ss; 4857416Smarkm#endif /* _SC_CRAY_SECURE_SYS */ 4957416Smarkm 5057416Smarkm#ifdef AUTHENTICATION 5157416Smarkmint auth_level = 0; 5257416Smarkm#endif 5357416Smarkm 54178825Sdfr#ifdef KRB5 55178825Sdfr#define Authenticator k5_Authenticator 56178825Sdfr#include <krb5.h> 57178825Sdfr#undef Authenticator 58178825Sdfr#endif 59178825Sdfr 6057416Smarkmextern int utmp_len; 6157416Smarkmint registerd_host_only = 0; 62178825Sdfr#ifdef ENCRYPTION 63178825Sdfrint require_encryption = 0; 64178825Sdfr#endif 6557416Smarkm 66178825Sdfr#ifdef STREAMSPTY 6790926Snectar 6857416Smarkm#ifdef _AIX 6957416Smarkm#include <sys/termio.h> 7057416Smarkm#endif 7157416Smarkm# ifdef HAVE_SYS_STRTTY_H 7257416Smarkm# include <sys/strtty.h> 7357416Smarkm# endif 7457416Smarkm# ifdef HAVE_SYS_STR_TTY_H 7557416Smarkm# include <sys/str_tty.h> 7657416Smarkm# endif 7757416Smarkm/* make sure we don't get the bsd version */ 7857416Smarkm/* what is this here for? solaris? /joda */ 7957416Smarkm# ifdef HAVE_SYS_TTY_H 8057416Smarkm# include "/usr/include/sys/tty.h" 8157416Smarkm# endif 8257416Smarkm# ifdef HAVE_SYS_PTYVAR_H 8357416Smarkm# include <sys/ptyvar.h> 8457416Smarkm# endif 8557416Smarkm 8657416Smarkm/* 8757416Smarkm * Because of the way ptyibuf is used with streams messages, we need 8857416Smarkm * ptyibuf+1 to be on a full-word boundary. The following wierdness 8957416Smarkm * is simply to make that happen. 9057416Smarkm */ 9157416Smarkmlong ptyibufbuf[BUFSIZ/sizeof(long)+1]; 9257416Smarkmchar *ptyibuf = ((char *)&ptyibufbuf[1])-1; 9357416Smarkmchar *ptyip = ((char *)&ptyibufbuf[1])-1; 9457416Smarkmchar ptyibuf2[BUFSIZ]; 9557416Smarkmunsigned char ctlbuf[BUFSIZ]; 9657416Smarkmstruct strbuf strbufc, strbufd; 9757416Smarkm 9857416Smarkmint readstream(int, char*, int); 9957416Smarkm 10057416Smarkm#else /* ! STREAMPTY */ 10157416Smarkm 10257416Smarkm/* 10357416Smarkm * I/O data buffers, 10457416Smarkm * pointers, and counters. 10557416Smarkm */ 10657416Smarkmchar ptyibuf[BUFSIZ], *ptyip = ptyibuf; 10757416Smarkmchar ptyibuf2[BUFSIZ]; 10857416Smarkm 10957416Smarkm#endif /* ! STREAMPTY */ 11057416Smarkm 11157416Smarkmint hostinfo = 1; /* do we print login banner? */ 11257416Smarkm 11357416Smarkm#ifdef _CRAY 11457416Smarkmextern int newmap; /* nonzero if \n maps to ^M^J */ 11557416Smarkmint lowpty = 0, highpty; /* low, high pty numbers */ 11657416Smarkm#endif /* CRAY */ 11757416Smarkm 11857416Smarkmint debug = 0; 11957416Smarkmint keepalive = 1; 12057416Smarkmchar *progname; 12157416Smarkm 122178825Sdfrstatic void usage (int error_code); 12357416Smarkm 12457416Smarkm/* 12557416Smarkm * The string to pass to getopt(). We do it this way so 12657416Smarkm * that only the actual options that we support will be 12757416Smarkm * passed off to getopt(). 12857416Smarkm */ 12957416Smarkmchar valid_opts[] = "Bd:hklnS:u:UL:y" 13057416Smarkm#ifdef AUTHENTICATION 13157416Smarkm "a:X:z" 13257416Smarkm#endif 133178825Sdfr#ifdef ENCRYPTION 134178825Sdfr "e" 135178825Sdfr#endif 13657416Smarkm#ifdef DIAGNOSTICS 13757416Smarkm "D:" 13857416Smarkm#endif 13957416Smarkm#ifdef _CRAY 14057416Smarkm "r:" 14157416Smarkm#endif 14257416Smarkm ; 14357416Smarkm 14457416Smarkmstatic void doit(struct sockaddr*, int); 14557416Smarkm 14657416Smarkmint 14757416Smarkmmain(int argc, char **argv) 14857416Smarkm{ 14957416Smarkm struct sockaddr_storage __ss; 15057416Smarkm struct sockaddr *sa = (struct sockaddr *)&__ss; 15172445Sassar int on = 1; 15272445Sassar socklen_t sa_size; 15357416Smarkm int ch; 15457416Smarkm#if defined(IPPROTO_IP) && defined(IP_TOS) 15557416Smarkm int tos = -1; 15657416Smarkm#endif 15757416Smarkm pfrontp = pbackp = ptyobuf; 15857416Smarkm netip = netibuf; 15957416Smarkm nfrontp = nbackp = netobuf; 16057416Smarkm 161127808Snectar setprogname(argv[0]); 162127808Snectar 16357416Smarkm progname = *argv; 16457416Smarkm#ifdef ENCRYPTION 16557416Smarkm nclearto = 0; 16657416Smarkm#endif 16757416Smarkm 16857416Smarkm#ifdef _CRAY 16957416Smarkm /* 17057416Smarkm * Get number of pty's before trying to process options, 17157416Smarkm * which may include changing pty range. 17257416Smarkm */ 17357416Smarkm highpty = getnpty(); 17457416Smarkm#endif /* CRAY */ 17557416Smarkm 176102644Snectar if (argc == 2 && strcmp(argv[1], "--version") == 0) { 177102644Snectar print_version(NULL); 178102644Snectar exit(0); 179102644Snectar } 180178825Sdfr if (argc == 2 && strcmp(argv[1], "--help") == 0) 181178825Sdfr usage(0); 182102644Snectar 18357416Smarkm while ((ch = getopt(argc, argv, valid_opts)) != -1) { 18457416Smarkm switch(ch) { 18557416Smarkm 18657416Smarkm#ifdef AUTHENTICATION 18757416Smarkm case 'a': 18857416Smarkm /* 18957416Smarkm * Check for required authentication level 19057416Smarkm */ 19157416Smarkm if (strcmp(optarg, "debug") == 0) { 19257416Smarkm auth_debug_mode = 1; 19357416Smarkm } else if (strcasecmp(optarg, "none") == 0) { 19457416Smarkm auth_level = 0; 19557416Smarkm } else if (strcasecmp(optarg, "otp") == 0) { 19657416Smarkm auth_level = 0; 19757416Smarkm require_otp = 1; 19857416Smarkm } else if (strcasecmp(optarg, "other") == 0) { 19957416Smarkm auth_level = AUTH_OTHER; 20057416Smarkm } else if (strcasecmp(optarg, "user") == 0) { 20157416Smarkm auth_level = AUTH_USER; 20257416Smarkm } else if (strcasecmp(optarg, "valid") == 0) { 20357416Smarkm auth_level = AUTH_VALID; 20457416Smarkm } else if (strcasecmp(optarg, "off") == 0) { 20557416Smarkm /* 20657416Smarkm * This hack turns off authentication 20757416Smarkm */ 20857416Smarkm auth_level = -1; 20957416Smarkm } else { 21057416Smarkm fprintf(stderr, 21157416Smarkm "telnetd: unknown authorization level for -a\n"); 21257416Smarkm } 21357416Smarkm break; 21457416Smarkm#endif /* AUTHENTICATION */ 21557416Smarkm 21657416Smarkm case 'B': /* BFTP mode is not supported any more */ 21757416Smarkm break; 21857416Smarkm case 'd': 21957416Smarkm if (strcmp(optarg, "ebug") == 0) { 22057416Smarkm debug++; 22157416Smarkm break; 22257416Smarkm } 223178825Sdfr usage(1); 22457416Smarkm /* NOTREACHED */ 22557416Smarkm break; 22657416Smarkm 22757416Smarkm#ifdef DIAGNOSTICS 22857416Smarkm case 'D': 22957416Smarkm /* 23057416Smarkm * Check for desired diagnostics capabilities. 23157416Smarkm */ 23257416Smarkm if (!strcmp(optarg, "report")) { 23357416Smarkm diagnostic |= TD_REPORT|TD_OPTIONS; 23457416Smarkm } else if (!strcmp(optarg, "exercise")) { 23557416Smarkm diagnostic |= TD_EXERCISE; 23657416Smarkm } else if (!strcmp(optarg, "netdata")) { 23757416Smarkm diagnostic |= TD_NETDATA; 23857416Smarkm } else if (!strcmp(optarg, "ptydata")) { 23957416Smarkm diagnostic |= TD_PTYDATA; 24057416Smarkm } else if (!strcmp(optarg, "options")) { 24157416Smarkm diagnostic |= TD_OPTIONS; 24257416Smarkm } else { 243178825Sdfr usage(1); 24457416Smarkm /* NOT REACHED */ 24557416Smarkm } 24657416Smarkm break; 24757416Smarkm#endif /* DIAGNOSTICS */ 24857416Smarkm 249178825Sdfr#ifdef ENCRYPTION 250178825Sdfr case 'e': 251178825Sdfr require_encryption = 1; 252178825Sdfr break; 253178825Sdfr#endif 25457416Smarkm 25557416Smarkm case 'h': 25657416Smarkm hostinfo = 0; 25757416Smarkm break; 25857416Smarkm 25957416Smarkm case 'k': /* Linemode is not supported any more */ 26057416Smarkm case 'l': 26157416Smarkm break; 26257416Smarkm 26357416Smarkm case 'n': 26457416Smarkm keepalive = 0; 26557416Smarkm break; 26657416Smarkm 26757416Smarkm#ifdef _CRAY 26857416Smarkm case 'r': 26957416Smarkm { 27057416Smarkm char *strchr(); 27157416Smarkm char *c; 27257416Smarkm 27357416Smarkm /* 27457416Smarkm * Allow the specification of alterations 27557416Smarkm * to the pty search range. It is legal to 27657416Smarkm * specify only one, and not change the 27757416Smarkm * other from its default. 27857416Smarkm */ 27957416Smarkm c = strchr(optarg, '-'); 28057416Smarkm if (c) { 28157416Smarkm *c++ = '\0'; 28257416Smarkm highpty = atoi(c); 28357416Smarkm } 28457416Smarkm if (*optarg != '\0') 28557416Smarkm lowpty = atoi(optarg); 28657416Smarkm if ((lowpty > highpty) || (lowpty < 0) || 28757416Smarkm (highpty > 32767)) { 288178825Sdfr usage(1); 28957416Smarkm /* NOT REACHED */ 29057416Smarkm } 29157416Smarkm break; 29257416Smarkm } 29357416Smarkm#endif /* CRAY */ 29457416Smarkm 29557416Smarkm case 'S': 29657416Smarkm#ifdef HAVE_PARSETOS 29757416Smarkm if ((tos = parsetos(optarg, "tcp")) < 0) 29857416Smarkm fprintf(stderr, "%s%s%s\n", 29957416Smarkm "telnetd: Bad TOS argument '", optarg, 30057416Smarkm "'; will try to use default TOS"); 30157416Smarkm#else 30257416Smarkm fprintf(stderr, "%s%s\n", "TOS option unavailable; ", 30357416Smarkm "-S flag not supported\n"); 30457416Smarkm#endif 30557416Smarkm break; 30657416Smarkm 30778527Sassar case 'u': { 30878527Sassar char *eptr; 30978527Sassar 31078527Sassar utmp_len = strtol(optarg, &eptr, 0); 31178527Sassar if (optarg == eptr) 31278527Sassar fprintf(stderr, "telnetd: unknown utmp len (%s)\n", optarg); 31357416Smarkm break; 31478527Sassar } 31557416Smarkm 31657416Smarkm case 'U': 31757416Smarkm registerd_host_only = 1; 31857416Smarkm break; 31957416Smarkm 32057416Smarkm#ifdef AUTHENTICATION 32157416Smarkm case 'X': 32257416Smarkm /* 32357416Smarkm * Check for invalid authentication types 32457416Smarkm */ 32557416Smarkm auth_disable_name(optarg); 32657416Smarkm break; 32757416Smarkm#endif 32857416Smarkm case 'y': 32957416Smarkm no_warn = 1; 33057416Smarkm break; 33157416Smarkm#ifdef AUTHENTICATION 33257416Smarkm case 'z': 33357416Smarkm log_unauth = 1; 33457416Smarkm break; 33557416Smarkm 33657416Smarkm#endif /* AUTHENTICATION */ 33757416Smarkm 33857416Smarkm case 'L': 33957416Smarkm new_login = optarg; 34057416Smarkm break; 341233294Sstas 34257416Smarkm default: 34357416Smarkm fprintf(stderr, "telnetd: %c: unknown option\n", ch); 34457416Smarkm /* FALLTHROUGH */ 34557416Smarkm case '?': 346178825Sdfr usage(0); 34757416Smarkm /* NOTREACHED */ 34857416Smarkm } 34957416Smarkm } 35057416Smarkm 35157416Smarkm argc -= optind; 35257416Smarkm argv += optind; 35357416Smarkm 35457416Smarkm if (debug) { 35557416Smarkm int port = 0; 35657416Smarkm struct servent *sp; 35757416Smarkm 35857416Smarkm if (argc > 1) { 359178825Sdfr usage (1); 36057416Smarkm } else if (argc == 1) { 36157416Smarkm sp = roken_getservbyname (*argv, "tcp"); 36257416Smarkm if (sp) 36357416Smarkm port = sp->s_port; 36457416Smarkm else 36557416Smarkm port = htons(atoi(*argv)); 36657416Smarkm } else { 36757416Smarkm#ifdef KRB5 36857416Smarkm port = krb5_getportbyname (NULL, "telnet", "tcp", 23); 36957416Smarkm#else 37057416Smarkm port = k_getportbyname("telnet", "tcp", htons(23)); 37157416Smarkm#endif 37257416Smarkm } 373233294Sstas mini_inetd (port, NULL); 37457416Smarkm } else if (argc > 0) { 375178825Sdfr usage(1); 37657416Smarkm /* NOT REACHED */ 37757416Smarkm } 37857416Smarkm 37957416Smarkm#ifdef _SC_CRAY_SECURE_SYS 38057416Smarkm secflag = sysconf(_SC_CRAY_SECURE_SYS); 38157416Smarkm 38257416Smarkm /* 38357416Smarkm * Get socket's security label 38457416Smarkm */ 38557416Smarkm if (secflag) { 38672445Sassar socklen_t szss = sizeof(ss); 38757416Smarkm int sock_multi; 38872445Sassar socklen_t szi = sizeof(int); 38957416Smarkm 39057416Smarkm memset(&dv, 0, sizeof(dv)); 39157416Smarkm 392233294Sstas if (getsysv(&sysv, sizeof(struct sysv)) != 0) 39357416Smarkm fatalperror(net, "getsysv"); 39457416Smarkm 39557416Smarkm /* 39657416Smarkm * Get socket security label and set device values 39757416Smarkm * {security label to be set on ttyp device} 39857416Smarkm */ 39957416Smarkm#ifdef SO_SEC_MULTI /* 8.0 code */ 40057416Smarkm if ((getsockopt(0, SOL_SOCKET, SO_SECURITY, 40157416Smarkm (void *)&ss, &szss) < 0) || 40257416Smarkm (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI, 403233294Sstas (void *)&sock_multi, &szi) < 0)) 40457416Smarkm fatalperror(net, "getsockopt"); 40557416Smarkm else { 40657416Smarkm dv.dv_actlvl = ss.ss_actlabel.lt_level; 40757416Smarkm dv.dv_actcmp = ss.ss_actlabel.lt_compart; 40857416Smarkm if (!sock_multi) { 40957416Smarkm dv.dv_minlvl = dv.dv_maxlvl = dv.dv_actlvl; 41057416Smarkm dv.dv_valcmp = dv.dv_actcmp; 41157416Smarkm } else { 41257416Smarkm dv.dv_minlvl = ss.ss_minlabel.lt_level; 41357416Smarkm dv.dv_maxlvl = ss.ss_maxlabel.lt_level; 41457416Smarkm dv.dv_valcmp = ss.ss_maxlabel.lt_compart; 41557416Smarkm } 41657416Smarkm dv.dv_devflg = 0; 41757416Smarkm } 41857416Smarkm#else /* SO_SEC_MULTI */ /* 7.0 code */ 41957416Smarkm if (getsockopt(0, SOL_SOCKET, SO_SECURITY, 42057416Smarkm (void *)&ss, &szss) >= 0) { 42157416Smarkm dv.dv_actlvl = ss.ss_slevel; 42257416Smarkm dv.dv_actcmp = ss.ss_compart; 42357416Smarkm dv.dv_minlvl = ss.ss_minlvl; 42457416Smarkm dv.dv_maxlvl = ss.ss_maxlvl; 42557416Smarkm dv.dv_valcmp = ss.ss_maxcmp; 42657416Smarkm } 42757416Smarkm#endif /* SO_SEC_MULTI */ 42857416Smarkm } 42957416Smarkm#endif /* _SC_CRAY_SECURE_SYS */ 43057416Smarkm 43157416Smarkm roken_openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON); 43257416Smarkm sa_size = sizeof (__ss); 43357416Smarkm if (getpeername(STDIN_FILENO, sa, &sa_size) < 0) { 43457416Smarkm fprintf(stderr, "%s: ", progname); 43557416Smarkm perror("getpeername"); 43657416Smarkm _exit(1); 43757416Smarkm } 43857416Smarkm if (keepalive && 43957416Smarkm setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, 44057416Smarkm (void *)&on, sizeof (on)) < 0) { 44157416Smarkm syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 44257416Smarkm } 44357416Smarkm 44457416Smarkm#if defined(IPPROTO_IP) && defined(IP_TOS) && defined(HAVE_SETSOCKOPT) 44557416Smarkm { 44657416Smarkm# ifdef HAVE_GETTOSBYNAME 44757416Smarkm struct tosent *tp; 44857416Smarkm if (tos < 0 && (tp = gettosbyname("telnet", "tcp"))) 44957416Smarkm tos = tp->t_tos; 45057416Smarkm# endif 45157416Smarkm if (tos < 0) 45257416Smarkm tos = 020; /* Low Delay bit */ 45357416Smarkm if (tos 45457416Smarkm && sa->sa_family == AF_INET 45557416Smarkm && (setsockopt(STDIN_FILENO, IPPROTO_IP, IP_TOS, 45657416Smarkm (void *)&tos, sizeof(tos)) < 0) 45757416Smarkm && (errno != ENOPROTOOPT) ) 45857416Smarkm syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 45957416Smarkm } 46057416Smarkm#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ 46157416Smarkm net = STDIN_FILENO; 46257416Smarkm doit(sa, sa_size); 46357416Smarkm /* NOTREACHED */ 46457416Smarkm return 0; 46557416Smarkm} /* end of main */ 46657416Smarkm 46757416Smarkmstatic void 468178825Sdfrusage(int exit_code) 46957416Smarkm{ 47057416Smarkm fprintf(stderr, "Usage: telnetd"); 471178825Sdfr fprintf(stderr, " [--help]"); 472178825Sdfr fprintf(stderr, " [--version]"); 47357416Smarkm#ifdef AUTHENTICATION 47457416Smarkm fprintf(stderr, " [-a (debug|other|otp|user|valid|off|none)]\n\t"); 47557416Smarkm#endif 47657416Smarkm fprintf(stderr, " [-debug]"); 47757416Smarkm#ifdef DIAGNOSTICS 47857416Smarkm fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t"); 47957416Smarkm#endif 48057416Smarkm#ifdef AUTHENTICATION 48157416Smarkm fprintf(stderr, " [-edebug]"); 48257416Smarkm#endif 48357416Smarkm fprintf(stderr, " [-h]"); 48457416Smarkm fprintf(stderr, " [-L login]"); 48557416Smarkm fprintf(stderr, " [-n]"); 48657416Smarkm#ifdef _CRAY 48757416Smarkm fprintf(stderr, " [-r[lowpty]-[highpty]]"); 48857416Smarkm#endif 48957416Smarkm fprintf(stderr, "\n\t"); 49057416Smarkm#ifdef HAVE_GETTOSBYNAME 49157416Smarkm fprintf(stderr, " [-S tos]"); 49257416Smarkm#endif 49357416Smarkm#ifdef AUTHENTICATION 49457416Smarkm fprintf(stderr, " [-X auth-type] [-y] [-z]"); 49557416Smarkm#endif 49657416Smarkm fprintf(stderr, " [-u utmp_hostname_length] [-U]"); 49757416Smarkm fprintf(stderr, " [port]\n"); 498178825Sdfr exit(exit_code); 49957416Smarkm} 50057416Smarkm 50157416Smarkm/* 50257416Smarkm * getterminaltype 50357416Smarkm * 50457416Smarkm * Ask the other end to send along its terminal type and speed. 50557416Smarkm * Output is the variable terminaltype filled in. 50657416Smarkm */ 50757416Smarkmstatic unsigned char ttytype_sbbuf[] = { 50857416Smarkm IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE 50957416Smarkm}; 51057416Smarkm 51157416Smarkmint 51257416Smarkmgetterminaltype(char *name, size_t name_sz) 51357416Smarkm{ 51457416Smarkm int retval = -1; 51557416Smarkm 51657416Smarkm settimer(baseline); 51757416Smarkm#ifdef AUTHENTICATION 51857416Smarkm /* 51957416Smarkm * Handle the Authentication option before we do anything else. 52057416Smarkm */ 52157416Smarkm send_do(TELOPT_AUTHENTICATION, 1); 52257416Smarkm while (his_will_wont_is_changing(TELOPT_AUTHENTICATION)) 52357416Smarkm ttloop(); 52457416Smarkm if (his_state_is_will(TELOPT_AUTHENTICATION)) { 52557416Smarkm retval = auth_wait(name, name_sz); 52657416Smarkm } 52757416Smarkm#endif 52857416Smarkm 52957416Smarkm#ifdef ENCRYPTION 53057416Smarkm send_will(TELOPT_ENCRYPT, 1); 53157416Smarkm send_do(TELOPT_ENCRYPT, 1); /* esc@magic.fi */ 53257416Smarkm#endif 53357416Smarkm send_do(TELOPT_TTYPE, 1); 53457416Smarkm send_do(TELOPT_TSPEED, 1); 53557416Smarkm send_do(TELOPT_XDISPLOC, 1); 53657416Smarkm send_do(TELOPT_NEW_ENVIRON, 1); 53757416Smarkm send_do(TELOPT_OLD_ENVIRON, 1); 53857416Smarkm while ( 53957416Smarkm#ifdef ENCRYPTION 54057416Smarkm his_do_dont_is_changing(TELOPT_ENCRYPT) || 54157416Smarkm#endif 54257416Smarkm his_will_wont_is_changing(TELOPT_TTYPE) || 54357416Smarkm his_will_wont_is_changing(TELOPT_TSPEED) || 54457416Smarkm his_will_wont_is_changing(TELOPT_XDISPLOC) || 54557416Smarkm his_will_wont_is_changing(TELOPT_NEW_ENVIRON) || 54657416Smarkm his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) { 54757416Smarkm ttloop(); 54857416Smarkm } 54957416Smarkm#ifdef ENCRYPTION 55057416Smarkm /* 55157416Smarkm * Wait for the negotiation of what type of encryption we can 55257416Smarkm * send with. If autoencrypt is not set, this will just return. 55357416Smarkm */ 55457416Smarkm if (his_state_is_will(TELOPT_ENCRYPT)) { 55557416Smarkm encrypt_wait(); 55657416Smarkm } 557178825Sdfr if (require_encryption) { 558178825Sdfr 559178825Sdfr while (encrypt_delay()) 560178825Sdfr if (telnet_spin()) 561178825Sdfr fatal(net, "Failed while waiting for encryption"); 562178825Sdfr 563178825Sdfr if (!encrypt_is_encrypting()) 564178825Sdfr fatal(net, "Encryption required but not turned on by client"); 565178825Sdfr } 56657416Smarkm#endif 56757416Smarkm if (his_state_is_will(TELOPT_TSPEED)) { 56857416Smarkm static unsigned char sb[] = 56957416Smarkm { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE }; 57057416Smarkm 57157416Smarkm telnet_net_write (sb, sizeof sb); 57257416Smarkm DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); 57357416Smarkm } 57457416Smarkm if (his_state_is_will(TELOPT_XDISPLOC)) { 57557416Smarkm static unsigned char sb[] = 57657416Smarkm { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE }; 57757416Smarkm 57857416Smarkm telnet_net_write (sb, sizeof sb); 57957416Smarkm DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); 58057416Smarkm } 58157416Smarkm if (his_state_is_will(TELOPT_NEW_ENVIRON)) { 58257416Smarkm static unsigned char sb[] = 58357416Smarkm { IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE }; 58457416Smarkm 58557416Smarkm telnet_net_write (sb, sizeof sb); 58657416Smarkm DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); 58757416Smarkm } 58857416Smarkm else if (his_state_is_will(TELOPT_OLD_ENVIRON)) { 58957416Smarkm static unsigned char sb[] = 59057416Smarkm { IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE }; 59157416Smarkm 59257416Smarkm telnet_net_write (sb, sizeof sb); 59357416Smarkm DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); 59457416Smarkm } 59557416Smarkm if (his_state_is_will(TELOPT_TTYPE)) { 59657416Smarkm 59757416Smarkm telnet_net_write (ttytype_sbbuf, sizeof ttytype_sbbuf); 59857416Smarkm DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2, 59957416Smarkm sizeof ttytype_sbbuf - 2);); 60057416Smarkm } 60157416Smarkm if (his_state_is_will(TELOPT_TSPEED)) { 60257416Smarkm while (sequenceIs(tspeedsubopt, baseline)) 60357416Smarkm ttloop(); 60457416Smarkm } 60557416Smarkm if (his_state_is_will(TELOPT_XDISPLOC)) { 60657416Smarkm while (sequenceIs(xdisplocsubopt, baseline)) 60757416Smarkm ttloop(); 60857416Smarkm } 60957416Smarkm if (his_state_is_will(TELOPT_NEW_ENVIRON)) { 61057416Smarkm while (sequenceIs(environsubopt, baseline)) 61157416Smarkm ttloop(); 61257416Smarkm } 61357416Smarkm if (his_state_is_will(TELOPT_OLD_ENVIRON)) { 61457416Smarkm while (sequenceIs(oenvironsubopt, baseline)) 61557416Smarkm ttloop(); 61657416Smarkm } 61757416Smarkm if (his_state_is_will(TELOPT_TTYPE)) { 61857416Smarkm char first[256], last[256]; 61957416Smarkm 62057416Smarkm while (sequenceIs(ttypesubopt, baseline)) 62157416Smarkm ttloop(); 62257416Smarkm 62357416Smarkm /* 62457416Smarkm * If the other side has already disabled the option, then 62557416Smarkm * we have to just go with what we (might) have already gotten. 62657416Smarkm */ 62757416Smarkm if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) { 62857416Smarkm strlcpy(first, terminaltype, sizeof(first)); 62957416Smarkm for(;;) { 63057416Smarkm /* 63157416Smarkm * Save the unknown name, and request the next name. 63257416Smarkm */ 63357416Smarkm strlcpy(last, terminaltype, sizeof(last)); 63457416Smarkm _gettermname(); 63557416Smarkm if (terminaltypeok(terminaltype)) 63657416Smarkm break; 63757416Smarkm if ((strncmp(last, terminaltype, sizeof(last)) == 0) || 63857416Smarkm his_state_is_wont(TELOPT_TTYPE)) { 63957416Smarkm /* 64057416Smarkm * We've hit the end. If this is the same as 64157416Smarkm * the first name, just go with it. 64257416Smarkm */ 64357416Smarkm if (strncmp(first, terminaltype, sizeof(first)) == 0) 64457416Smarkm break; 64557416Smarkm /* 64657416Smarkm * Get the terminal name one more time, so that 64757416Smarkm * RFC1091 compliant telnets will cycle back to 64857416Smarkm * the start of the list. 64957416Smarkm */ 65057416Smarkm _gettermname(); 65157416Smarkm if (strncmp(first, terminaltype, sizeof(first)) != 0) 652178825Sdfr strlcpy(terminaltype, first, sizeof(terminaltype)); 65357416Smarkm break; 65457416Smarkm } 65557416Smarkm } 65657416Smarkm } 65757416Smarkm } 65857416Smarkm return(retval); 65957416Smarkm} /* end of getterminaltype */ 66057416Smarkm 66157416Smarkmvoid 66278527Sassar_gettermname(void) 66357416Smarkm{ 66457416Smarkm /* 66557416Smarkm * If the client turned off the option, 66657416Smarkm * we can't send another request, so we 66757416Smarkm * just return. 66857416Smarkm */ 66957416Smarkm if (his_state_is_wont(TELOPT_TTYPE)) 67057416Smarkm return; 67157416Smarkm settimer(baseline); 67257416Smarkm telnet_net_write (ttytype_sbbuf, sizeof ttytype_sbbuf); 67357416Smarkm DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2, 67457416Smarkm sizeof ttytype_sbbuf - 2);); 67557416Smarkm while (sequenceIs(ttypesubopt, baseline)) 67657416Smarkm ttloop(); 67757416Smarkm} 67857416Smarkm 67957416Smarkmint 68057416Smarkmterminaltypeok(char *s) 68157416Smarkm{ 68257416Smarkm return 1; 68357416Smarkm} 68457416Smarkm 68557416Smarkm 68657416Smarkmchar host_name[MaxHostNameLen]; 68757416Smarkmchar remote_host_name[MaxHostNameLen]; 68878527Sassarchar remote_utmp_name[MaxHostNameLen]; 68957416Smarkm 69057416Smarkm/* 69157416Smarkm * Get a pty, scan input lines. 69257416Smarkm */ 69357416Smarkmstatic void 69457416Smarkmdoit(struct sockaddr *who, int who_len) 69557416Smarkm{ 69657416Smarkm int level; 69757416Smarkm int ptynum; 69857416Smarkm char user_name[256]; 69957416Smarkm int error; 70057416Smarkm 70157416Smarkm /* 70257416Smarkm * Find an available pty to use. 70357416Smarkm */ 70457416Smarkm ourpty = getpty(&ptynum); 70557416Smarkm if (ourpty < 0) 70657416Smarkm fatal(net, "All network ports in use"); 70757416Smarkm 70857416Smarkm#ifdef _SC_CRAY_SECURE_SYS 70957416Smarkm /* 71057416Smarkm * set ttyp line security label 71157416Smarkm */ 71257416Smarkm if (secflag) { 71357416Smarkm char slave_dev[16]; 71457416Smarkm 71557416Smarkm snprintf(tty_dev, sizeof(tty_dev), "/dev/pty/%03d", ptynum); 71657416Smarkm if (setdevs(tty_dev, &dv) < 0) 71757416Smarkm fatal(net, "cannot set pty security"); 71857416Smarkm snprintf(slave_dev, sizeof(slave_dev), "/dev/ttyp%03d", ptynum); 71957416Smarkm if (setdevs(slave_dev, &dv) < 0) 72057416Smarkm fatal(net, "cannot set tty security"); 72157416Smarkm } 72257416Smarkm#endif /* _SC_CRAY_SECURE_SYS */ 72357416Smarkm 72478527Sassar error = getnameinfo_verified (who, who_len, 72578527Sassar remote_host_name, 72678527Sassar sizeof(remote_host_name), 727233294Sstas NULL, 0, 72857416Smarkm registerd_host_only ? NI_NAMEREQD : 0); 72957416Smarkm if (error) 73057416Smarkm fatal(net, "Couldn't resolve your address into a host name.\r\n\ 73157416SmarkmPlease contact your net administrator"); 73257416Smarkm 73357416Smarkm gethostname(host_name, sizeof (host_name)); 73457416Smarkm 73578527Sassar strlcpy (remote_utmp_name, remote_host_name, sizeof(remote_utmp_name)); 73678527Sassar 73757416Smarkm /* Only trim if too long (and possible) */ 73878527Sassar if (strlen(remote_utmp_name) > utmp_len) { 73957416Smarkm char *domain = strchr(host_name, '.'); 74078527Sassar char *p = strchr(remote_utmp_name, '.'); 74178527Sassar if (domain != NULL && p != NULL && (strcmp(p, domain) == 0)) 74278527Sassar *p = '\0'; /* remove domain part */ 74357416Smarkm } 74457416Smarkm 74557416Smarkm /* 74657416Smarkm * If hostname still doesn't fit utmp, use ipaddr. 74757416Smarkm */ 74878527Sassar if (strlen(remote_utmp_name) > utmp_len) { 74978527Sassar error = getnameinfo (who, who_len, 75078527Sassar remote_utmp_name, 75178527Sassar sizeof(remote_utmp_name), 75278527Sassar NULL, 0, 75378527Sassar NI_NUMERICHOST); 75478527Sassar if (error) 75578527Sassar fatal(net, "Couldn't get numeric address\r\n"); 75678527Sassar } 75757416Smarkm 75857416Smarkm#ifdef AUTHENTICATION 75978527Sassar auth_encrypt_init(host_name, remote_host_name, "TELNETD", 1); 76057416Smarkm#endif 76157416Smarkm 76257416Smarkm init_env(); 763178825Sdfr 764178825Sdfr /* begin server processing */ 765178825Sdfr 76657416Smarkm /* 767178825Sdfr * Initialize the slc mapping table. 768178825Sdfr */ 769178825Sdfr 770178825Sdfr get_slc_defaults(); 771178825Sdfr 772178825Sdfr /* 77357416Smarkm * get terminal type. 77457416Smarkm */ 77557416Smarkm *user_name = 0; 77657416Smarkm level = getterminaltype(user_name, sizeof(user_name)); 777178825Sdfr esetenv("TERM", terminaltype[0] ? terminaltype : "network", 1); 77857416Smarkm 77957416Smarkm#ifdef _SC_CRAY_SECURE_SYS 78057416Smarkm if (secflag) { 78157416Smarkm if (setulvl(dv.dv_actlvl) < 0) 78257416Smarkm fatal(net,"cannot setulvl()"); 78357416Smarkm if (setucmp(dv.dv_actcmp) < 0) 78457416Smarkm fatal(net, "cannot setucmp()"); 78557416Smarkm } 78657416Smarkm#endif /* _SC_CRAY_SECURE_SYS */ 78757416Smarkm 78878527Sassar my_telnet(net, ourpty, remote_host_name, remote_utmp_name, 78978527Sassar level, user_name); 79057416Smarkm /*NOTREACHED*/ 79157416Smarkm} /* end of doit */ 79257416Smarkm 79357416Smarkm/* output contents of /etc/issue.net, or /etc/issue */ 79457416Smarkmstatic void 79557416Smarkmshow_issue(void) 79657416Smarkm{ 79757416Smarkm FILE *f; 79857416Smarkm char buf[128]; 799102644Snectar f = fopen(SYSCONFDIR "/issue.net", "r"); 80057416Smarkm if(f == NULL) 801102644Snectar f = fopen(SYSCONFDIR "/issue", "r"); 80257416Smarkm if(f){ 803178825Sdfr while(fgets(buf, sizeof(buf), f) != NULL) { 804178825Sdfr size_t len = strcspn(buf, "\r\n"); 805178825Sdfr if(len == strlen(buf)) { 806178825Sdfr /* there's no newline */ 807178825Sdfr writenet(buf, len); 808178825Sdfr } else { 809178825Sdfr /* replace newline with \r\n */ 810178825Sdfr buf[len] = '\0'; 811178825Sdfr writenet(buf, len); 812178825Sdfr writenet("\r\n", 2); 813178825Sdfr } 81457416Smarkm } 81557416Smarkm fclose(f); 81657416Smarkm } 81757416Smarkm} 81857416Smarkm 81957416Smarkm/* 82057416Smarkm * Main loop. Select from pty and network, and 82157416Smarkm * hand data to telnet receiver finite state machine. 82257416Smarkm */ 82357416Smarkmvoid 82478527Sassarmy_telnet(int f, int p, const char *host, const char *utmp_host, 82578527Sassar int level, char *autoname) 82657416Smarkm{ 82757416Smarkm int on = 1; 82857416Smarkm char *he; 82957416Smarkm char *IM; 83057416Smarkm int nfd; 83157416Smarkm int startslave_called = 0; 83257416Smarkm time_t timeout; 83357416Smarkm 83457416Smarkm /* 83557416Smarkm * Do some tests where it is desireable to wait for a response. 83657416Smarkm * Rather than doing them slowly, one at a time, do them all 83757416Smarkm * at once. 83857416Smarkm */ 83957416Smarkm if (my_state_is_wont(TELOPT_SGA)) 84057416Smarkm send_will(TELOPT_SGA, 1); 84157416Smarkm /* 84257416Smarkm * Is the client side a 4.2 (NOT 4.3) system? We need to know this 84357416Smarkm * because 4.2 clients are unable to deal with TCP urgent data. 84457416Smarkm * 84557416Smarkm * To find out, we send out a "DO ECHO". If the remote system 84657416Smarkm * answers "WILL ECHO" it is probably a 4.2 client, and we note 84757416Smarkm * that fact ("WILL ECHO" ==> that the client will echo what 84857416Smarkm * WE, the server, sends it; it does NOT mean that the client will 84957416Smarkm * echo the terminal input). 85057416Smarkm */ 85157416Smarkm send_do(TELOPT_ECHO, 1); 85257416Smarkm 85357416Smarkm /* 85457416Smarkm * Send along a couple of other options that we wish to negotiate. 85557416Smarkm */ 85657416Smarkm send_do(TELOPT_NAWS, 1); 85757416Smarkm send_will(TELOPT_STATUS, 1); 85857416Smarkm flowmode = 1; /* default flow control state */ 85957416Smarkm restartany = -1; /* uninitialized... */ 86057416Smarkm send_do(TELOPT_LFLOW, 1); 86157416Smarkm 86257416Smarkm /* 86357416Smarkm * Spin, waiting for a response from the DO ECHO. However, 86457416Smarkm * some REALLY DUMB telnets out there might not respond 86557416Smarkm * to the DO ECHO. So, we spin looking for NAWS, (most dumb 86657416Smarkm * telnets so far seem to respond with WONT for a DO that 86757416Smarkm * they don't understand...) because by the time we get the 86857416Smarkm * response, it will already have processed the DO ECHO. 86957416Smarkm * Kludge upon kludge. 87057416Smarkm */ 87157416Smarkm while (his_will_wont_is_changing(TELOPT_NAWS)) 87257416Smarkm ttloop(); 87357416Smarkm 87457416Smarkm /* 87557416Smarkm * But... 87657416Smarkm * The client might have sent a WILL NAWS as part of its 87757416Smarkm * startup code; if so, we'll be here before we get the 87857416Smarkm * response to the DO ECHO. We'll make the assumption 87957416Smarkm * that any implementation that understands about NAWS 88057416Smarkm * is a modern enough implementation that it will respond 88157416Smarkm * to our DO ECHO request; hence we'll do another spin 88257416Smarkm * waiting for the ECHO option to settle down, which is 88357416Smarkm * what we wanted to do in the first place... 88457416Smarkm */ 88557416Smarkm if (his_want_state_is_will(TELOPT_ECHO) && 88657416Smarkm his_state_is_will(TELOPT_NAWS)) { 88757416Smarkm while (his_will_wont_is_changing(TELOPT_ECHO)) 88857416Smarkm ttloop(); 88957416Smarkm } 89057416Smarkm /* 89157416Smarkm * On the off chance that the telnet client is broken and does not 89257416Smarkm * respond to the DO ECHO we sent, (after all, we did send the 89357416Smarkm * DO NAWS negotiation after the DO ECHO, and we won't get here 89457416Smarkm * until a response to the DO NAWS comes back) simulate the 89557416Smarkm * receipt of a will echo. This will also send a WONT ECHO 89657416Smarkm * to the client, since we assume that the client failed to 89757416Smarkm * respond because it believes that it is already in DO ECHO 89857416Smarkm * mode, which we do not want. 89957416Smarkm */ 90057416Smarkm if (his_want_state_is_will(TELOPT_ECHO)) { 90157416Smarkm DIAG(TD_OPTIONS, 90257416Smarkm {output_data("td: simulating recv\r\n"); 90357416Smarkm }); 90457416Smarkm willoption(TELOPT_ECHO); 90557416Smarkm } 90657416Smarkm 90757416Smarkm /* 90857416Smarkm * Finally, to clean things up, we turn on our echo. This 90957416Smarkm * will break stupid 4.2 telnets out of local terminal echo. 91057416Smarkm */ 91157416Smarkm 91257416Smarkm if (my_state_is_wont(TELOPT_ECHO)) 91357416Smarkm send_will(TELOPT_ECHO, 1); 91457416Smarkm 91557416Smarkm#ifdef TIOCPKT 91657416Smarkm#ifdef STREAMSPTY 91757416Smarkm if (!really_stream) 91857416Smarkm#endif 91957416Smarkm /* 92057416Smarkm * Turn on packet mode 92157416Smarkm */ 92257416Smarkm ioctl(p, TIOCPKT, (char *)&on); 92357416Smarkm#endif 92457416Smarkm 92557416Smarkm 92657416Smarkm /* 92757416Smarkm * Call telrcv() once to pick up anything received during 92857416Smarkm * terminal type negotiation, 4.2/4.3 determination, and 92957416Smarkm * linemode negotiation. 93057416Smarkm */ 93157416Smarkm telrcv(); 93257416Smarkm 93357416Smarkm ioctl(f, FIONBIO, (char *)&on); 93457416Smarkm ioctl(p, FIONBIO, (char *)&on); 93557416Smarkm 93657416Smarkm#if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT) 93757416Smarkm setsockopt(net, SOL_SOCKET, SO_OOBINLINE, 93857416Smarkm (void *)&on, sizeof on); 93957416Smarkm#endif /* defined(SO_OOBINLINE) */ 94057416Smarkm 94157416Smarkm#ifdef SIGTSTP 94257416Smarkm signal(SIGTSTP, SIG_IGN); 94357416Smarkm#endif 94457416Smarkm#ifdef SIGTTOU 94557416Smarkm /* 94657416Smarkm * Ignoring SIGTTOU keeps the kernel from blocking us 94757416Smarkm * in ttioct() in /sys/tty.c. 94857416Smarkm */ 94957416Smarkm signal(SIGTTOU, SIG_IGN); 95057416Smarkm#endif 95157416Smarkm 95257416Smarkm signal(SIGCHLD, cleanup); 95357416Smarkm 95457416Smarkm#ifdef TIOCNOTTY 95557416Smarkm { 95657416Smarkm int t; 95757416Smarkm t = open(_PATH_TTY, O_RDWR); 95857416Smarkm if (t >= 0) { 95957416Smarkm ioctl(t, TIOCNOTTY, (char *)0); 96057416Smarkm close(t); 96157416Smarkm } 96257416Smarkm } 96357416Smarkm#endif 96457416Smarkm 96557416Smarkm show_issue(); 96657416Smarkm /* 96757416Smarkm * Show banner that getty never gave. 96857416Smarkm * 96957416Smarkm * We put the banner in the pty input buffer. This way, it 97057416Smarkm * gets carriage return null processing, etc., just like all 97157416Smarkm * other pty --> client data. 97257416Smarkm */ 97357416Smarkm 97457416Smarkm if (getenv("USER")) 97557416Smarkm hostinfo = 0; 97657416Smarkm 97757416Smarkm IM = DEFAULT_IM; 97857416Smarkm he = 0; 97957416Smarkm edithost(he, host_name); 98057416Smarkm if (hostinfo && *IM) 98157416Smarkm putf(IM, ptyibuf2); 98257416Smarkm 98357416Smarkm if (pcc) 98457416Smarkm strncat(ptyibuf2, ptyip, pcc+1); 98557416Smarkm ptyip = ptyibuf2; 98657416Smarkm pcc = strlen(ptyip); 98757416Smarkm 98857416Smarkm DIAG(TD_REPORT, { 98957416Smarkm output_data("td: Entering processing loop\r\n"); 99057416Smarkm }); 99157416Smarkm 99257416Smarkm 99357416Smarkm nfd = ((f > p) ? f : p) + 1; 99457416Smarkm timeout = time(NULL) + 5; 99557416Smarkm for (;;) { 99657416Smarkm fd_set ibits, obits, xbits; 99757416Smarkm int c; 99857416Smarkm 99957416Smarkm /* wait for encryption to be turned on, but don't wait 100057416Smarkm indefinitely */ 100157416Smarkm if(!startslave_called && (!encrypt_delay() || timeout > time(NULL))){ 100257416Smarkm startslave_called = 1; 100378527Sassar startslave(host, utmp_host, level, autoname); 100457416Smarkm } 100557416Smarkm 100657416Smarkm if (ncc < 0 && pcc < 0) 100757416Smarkm break; 100857416Smarkm 100957416Smarkm FD_ZERO(&ibits); 101057416Smarkm FD_ZERO(&obits); 101157416Smarkm FD_ZERO(&xbits); 101272445Sassar 101372445Sassar if (f >= FD_SETSIZE 101472445Sassar || p >= FD_SETSIZE) 101572445Sassar fatal(net, "fd too large"); 101672445Sassar 101757416Smarkm /* 101857416Smarkm * Never look for input if there's still 101957416Smarkm * stuff in the corresponding output buffer 102057416Smarkm */ 102157416Smarkm if (nfrontp - nbackp || pcc > 0) { 102257416Smarkm FD_SET(f, &obits); 102357416Smarkm } else { 102457416Smarkm FD_SET(p, &ibits); 102557416Smarkm } 102657416Smarkm if (pfrontp - pbackp || ncc > 0) { 102757416Smarkm FD_SET(p, &obits); 102857416Smarkm } else { 102957416Smarkm FD_SET(f, &ibits); 103057416Smarkm } 103157416Smarkm if (!SYNCHing) { 103257416Smarkm FD_SET(f, &xbits); 103357416Smarkm } 103457416Smarkm if ((c = select(nfd, &ibits, &obits, &xbits, 103557416Smarkm (struct timeval *)0)) < 1) { 103657416Smarkm if (c == -1) { 103757416Smarkm if (errno == EINTR) { 103857416Smarkm continue; 103957416Smarkm } 104057416Smarkm } 104157416Smarkm sleep(5); 104257416Smarkm continue; 104357416Smarkm } 104457416Smarkm 104557416Smarkm /* 104657416Smarkm * Any urgent data? 104757416Smarkm */ 104857416Smarkm if (FD_ISSET(net, &xbits)) { 104957416Smarkm SYNCHing = 1; 105057416Smarkm } 105157416Smarkm 105257416Smarkm /* 105357416Smarkm * Something to read from the network... 105457416Smarkm */ 105557416Smarkm if (FD_ISSET(net, &ibits)) { 105657416Smarkm#ifndef SO_OOBINLINE 105757416Smarkm /* 105857416Smarkm * In 4.2 (and 4.3 beta) systems, the 105957416Smarkm * OOB indication and data handling in the kernel 106057416Smarkm * is such that if two separate TCP Urgent requests 106157416Smarkm * come in, one byte of TCP data will be overlaid. 106257416Smarkm * This is fatal for Telnet, but we try to live 106357416Smarkm * with it. 106457416Smarkm * 106557416Smarkm * In addition, in 4.2 (and...), a special protocol 106657416Smarkm * is needed to pick up the TCP Urgent data in 106757416Smarkm * the correct sequence. 106857416Smarkm * 106957416Smarkm * What we do is: if we think we are in urgent 107057416Smarkm * mode, we look to see if we are "at the mark". 107157416Smarkm * If we are, we do an OOB receive. If we run 107257416Smarkm * this twice, we will do the OOB receive twice, 107357416Smarkm * but the second will fail, since the second 107457416Smarkm * time we were "at the mark", but there wasn't 107557416Smarkm * any data there (the kernel doesn't reset 107657416Smarkm * "at the mark" until we do a normal read). 107757416Smarkm * Once we've read the OOB data, we go ahead 107857416Smarkm * and do normal reads. 107957416Smarkm * 108057416Smarkm * There is also another problem, which is that 108157416Smarkm * since the OOB byte we read doesn't put us 108257416Smarkm * out of OOB state, and since that byte is most 108357416Smarkm * likely the TELNET DM (data mark), we would 108457416Smarkm * stay in the TELNET SYNCH (SYNCHing) state. 108557416Smarkm * So, clocks to the rescue. If we've "just" 108657416Smarkm * received a DM, then we test for the 108757416Smarkm * presence of OOB data when the receive OOB 108857416Smarkm * fails (and AFTER we did the normal mode read 108957416Smarkm * to clear "at the mark"). 109057416Smarkm */ 109157416Smarkm if (SYNCHing) { 109257416Smarkm int atmark; 109357416Smarkm 109457416Smarkm ioctl(net, SIOCATMARK, (char *)&atmark); 109557416Smarkm if (atmark) { 109657416Smarkm ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB); 109757416Smarkm if ((ncc == -1) && (errno == EINVAL)) { 109857416Smarkm ncc = read(net, netibuf, sizeof (netibuf)); 109957416Smarkm if (sequenceIs(didnetreceive, gotDM)) { 110057416Smarkm SYNCHing = stilloob(net); 110157416Smarkm } 110257416Smarkm } 110357416Smarkm } else { 110457416Smarkm ncc = read(net, netibuf, sizeof (netibuf)); 110557416Smarkm } 110657416Smarkm } else { 110757416Smarkm ncc = read(net, netibuf, sizeof (netibuf)); 110857416Smarkm } 110957416Smarkm settimer(didnetreceive); 111057416Smarkm#else /* !defined(SO_OOBINLINE)) */ 111157416Smarkm ncc = read(net, netibuf, sizeof (netibuf)); 111257416Smarkm#endif /* !defined(SO_OOBINLINE)) */ 111357416Smarkm if (ncc < 0 && errno == EWOULDBLOCK) 111457416Smarkm ncc = 0; 111557416Smarkm else { 111657416Smarkm if (ncc <= 0) { 111757416Smarkm break; 111857416Smarkm } 111957416Smarkm netip = netibuf; 112057416Smarkm } 112157416Smarkm DIAG((TD_REPORT | TD_NETDATA), { 112257416Smarkm output_data("td: netread %d chars\r\n", ncc); 112357416Smarkm }); 112457416Smarkm DIAG(TD_NETDATA, printdata("nd", netip, ncc)); 112557416Smarkm } 112657416Smarkm 112757416Smarkm /* 112857416Smarkm * Something to read from the pty... 112957416Smarkm */ 113057416Smarkm if (FD_ISSET(p, &ibits)) { 113157416Smarkm#ifdef STREAMSPTY 113257416Smarkm if (really_stream) 113357416Smarkm pcc = readstream(p, ptyibuf, BUFSIZ); 113457416Smarkm else 113557416Smarkm#endif 113657416Smarkm pcc = read(p, ptyibuf, BUFSIZ); 113757416Smarkm 113857416Smarkm /* 113957416Smarkm * On some systems, if we try to read something 114057416Smarkm * off the master side before the slave side is 114157416Smarkm * opened, we get EIO. 114257416Smarkm */ 114357416Smarkm if (pcc < 0 && (errno == EWOULDBLOCK || 114457416Smarkm#ifdef EAGAIN 114557416Smarkm errno == EAGAIN || 114657416Smarkm#endif 114757416Smarkm errno == EIO)) { 114857416Smarkm pcc = 0; 114957416Smarkm } else { 115057416Smarkm if (pcc <= 0) 115157416Smarkm break; 115257416Smarkm if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) { 115357416Smarkm netclear(); /* clear buffer back */ 115457416Smarkm#ifndef NO_URGENT 115557416Smarkm /* 115657416Smarkm * There are client telnets on some 115757416Smarkm * operating systems get screwed up 115857416Smarkm * royally if we send them urgent 115957416Smarkm * mode data. 116057416Smarkm */ 116157416Smarkm output_data ("%c%c", IAC, DM); 116257416Smarkm 116357416Smarkm neturg = nfrontp-1; /* off by one XXX */ 116457416Smarkm DIAG(TD_OPTIONS, 116557416Smarkm printoption("td: send IAC", DM)); 116657416Smarkm 116757416Smarkm#endif 116857416Smarkm } 116957416Smarkm if (his_state_is_will(TELOPT_LFLOW) && 117057416Smarkm (ptyibuf[0] & 117157416Smarkm (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) { 117257416Smarkm int newflow = 117357416Smarkm ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0; 117457416Smarkm if (newflow != flowmode) { 117557416Smarkm flowmode = newflow; 117657416Smarkm output_data("%c%c%c%c%c%c", 117757416Smarkm IAC, SB, TELOPT_LFLOW, 117857416Smarkm flowmode ? LFLOW_ON 117957416Smarkm : LFLOW_OFF, 118057416Smarkm IAC, SE); 118157416Smarkm DIAG(TD_OPTIONS, printsub('>', 118257416Smarkm (unsigned char *)nfrontp-4, 118357416Smarkm 4);); 118457416Smarkm } 118557416Smarkm } 118657416Smarkm pcc--; 118757416Smarkm ptyip = ptyibuf+1; 118857416Smarkm } 118957416Smarkm } 119057416Smarkm 119157416Smarkm while (pcc > 0) { 119257416Smarkm if ((&netobuf[BUFSIZ] - nfrontp) < 3) 119357416Smarkm break; 119457416Smarkm c = *ptyip++ & 0377, pcc--; 119557416Smarkm if (c == IAC) 119657416Smarkm *nfrontp++ = c; 119757416Smarkm *nfrontp++ = c; 119857416Smarkm if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) { 119957416Smarkm if (pcc > 0 && ((*ptyip & 0377) == '\n')) { 120057416Smarkm *nfrontp++ = *ptyip++ & 0377; 120157416Smarkm pcc--; 120257416Smarkm } else 120357416Smarkm *nfrontp++ = '\0'; 120457416Smarkm } 120557416Smarkm } 120657416Smarkm 120757416Smarkm if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0) 120857416Smarkm netflush(); 120957416Smarkm if (ncc > 0) 121057416Smarkm telrcv(); 121157416Smarkm if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0) 121257416Smarkm ptyflush(); 121357416Smarkm } 121457416Smarkm cleanup(0); 121557416Smarkm} 121657416Smarkm 121757416Smarkm#ifndef TCSIG 121857416Smarkm# ifdef TIOCSIG 121957416Smarkm# define TCSIG TIOCSIG 122057416Smarkm# endif 122157416Smarkm#endif 122257416Smarkm 122357416Smarkm#ifdef STREAMSPTY 122457416Smarkm 122557416Smarkm int flowison = -1; /* current state of flow: -1 is unknown */ 122657416Smarkm 122757416Smarkmint 122857416Smarkmreadstream(int p, char *ibuf, int bufsize) 122957416Smarkm{ 123057416Smarkm int flags = 0; 123157416Smarkm int ret = 0; 123257416Smarkm struct termios *tsp; 123357416Smarkm#if 0 123457416Smarkm struct termio *tp; 123557416Smarkm#endif 123657416Smarkm struct iocblk *ip; 123757416Smarkm char vstop, vstart; 123857416Smarkm int ixon; 123957416Smarkm int newflow; 124057416Smarkm 124157416Smarkm strbufc.maxlen = BUFSIZ; 124257416Smarkm strbufc.buf = (char *)ctlbuf; 124357416Smarkm strbufd.maxlen = bufsize-1; 124457416Smarkm strbufd.len = 0; 124557416Smarkm strbufd.buf = ibuf+1; 124657416Smarkm ibuf[0] = 0; 124757416Smarkm 124857416Smarkm ret = getmsg(p, &strbufc, &strbufd, &flags); 124957416Smarkm if (ret < 0) /* error of some sort -- probably EAGAIN */ 125057416Smarkm return(-1); 125157416Smarkm 125257416Smarkm if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) { 125357416Smarkm /* data message */ 125457416Smarkm if (strbufd.len > 0) { /* real data */ 125557416Smarkm return(strbufd.len + 1); /* count header char */ 125657416Smarkm } else { 125757416Smarkm /* nothing there */ 125857416Smarkm errno = EAGAIN; 125957416Smarkm return(-1); 126057416Smarkm } 126157416Smarkm } 126257416Smarkm 126357416Smarkm /* 126457416Smarkm * It's a control message. Return 1, to look at the flag we set 126557416Smarkm */ 126657416Smarkm 126757416Smarkm switch (ctlbuf[0]) { 126857416Smarkm case M_FLUSH: 126957416Smarkm if (ibuf[1] & FLUSHW) 127057416Smarkm ibuf[0] = TIOCPKT_FLUSHWRITE; 127157416Smarkm return(1); 127257416Smarkm 127357416Smarkm case M_IOCTL: 127457416Smarkm ip = (struct iocblk *) (ibuf+1); 127557416Smarkm 127657416Smarkm switch (ip->ioc_cmd) { 127757416Smarkm#ifdef TCSETS 127857416Smarkm case TCSETS: 127957416Smarkm case TCSETSW: 128057416Smarkm case TCSETSF: 128157416Smarkm tsp = (struct termios *) 128257416Smarkm (ibuf+1 + sizeof(struct iocblk)); 128357416Smarkm vstop = tsp->c_cc[VSTOP]; 128457416Smarkm vstart = tsp->c_cc[VSTART]; 128557416Smarkm ixon = tsp->c_iflag & IXON; 128657416Smarkm break; 128757416Smarkm#endif 128857416Smarkm#if 0 128957416Smarkm case TCSETA: 129057416Smarkm case TCSETAW: 129157416Smarkm case TCSETAF: 129257416Smarkm tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk)); 129357416Smarkm vstop = tp->c_cc[VSTOP]; 129457416Smarkm vstart = tp->c_cc[VSTART]; 129557416Smarkm ixon = tp->c_iflag & IXON; 129657416Smarkm break; 129757416Smarkm#endif 129857416Smarkm default: 129957416Smarkm errno = EAGAIN; 130057416Smarkm return(-1); 130157416Smarkm } 130257416Smarkm 130357416Smarkm newflow = (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0; 130457416Smarkm if (newflow != flowison) { /* it's a change */ 130557416Smarkm flowison = newflow; 130657416Smarkm ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP; 130757416Smarkm return(1); 130857416Smarkm } 130957416Smarkm } 131057416Smarkm 131157416Smarkm /* nothing worth doing anything about */ 131257416Smarkm errno = EAGAIN; 131357416Smarkm return(-1); 131457416Smarkm} 131557416Smarkm#endif /* STREAMSPTY */ 131657416Smarkm 131757416Smarkm/* 131857416Smarkm * Send interrupt to process on other side of pty. 131957416Smarkm * If it is in raw mode, just write NULL; 132057416Smarkm * otherwise, write intr char. 132157416Smarkm */ 132257416Smarkmvoid 132357416Smarkminterrupt() 132457416Smarkm{ 132557416Smarkm ptyflush(); /* half-hearted */ 132657416Smarkm 132757416Smarkm#if defined(STREAMSPTY) && defined(TIOCSIGNAL) 132857416Smarkm /* Streams PTY style ioctl to post a signal */ 132957416Smarkm if (really_stream) 133057416Smarkm { 133157416Smarkm int sig = SIGINT; 133257416Smarkm ioctl(ourpty, TIOCSIGNAL, &sig); 133357416Smarkm ioctl(ourpty, I_FLUSH, FLUSHR); 133457416Smarkm } 133557416Smarkm#else 133657416Smarkm#ifdef TCSIG 133757416Smarkm ioctl(ourpty, TCSIG, (char *)SIGINT); 133857416Smarkm#else /* TCSIG */ 133957416Smarkm init_termbuf(); 134057416Smarkm *pfrontp++ = slctab[SLC_IP].sptr ? 134157416Smarkm (unsigned char)*slctab[SLC_IP].sptr : '\177'; 134257416Smarkm#endif /* TCSIG */ 134357416Smarkm#endif 134457416Smarkm} 134557416Smarkm 134657416Smarkm/* 134757416Smarkm * Send quit to process on other side of pty. 134857416Smarkm * If it is in raw mode, just write NULL; 134957416Smarkm * otherwise, write quit char. 135057416Smarkm */ 135157416Smarkmvoid 135257416Smarkmsendbrk() 135357416Smarkm{ 135457416Smarkm ptyflush(); /* half-hearted */ 135557416Smarkm#ifdef TCSIG 135657416Smarkm ioctl(ourpty, TCSIG, (char *)SIGQUIT); 135757416Smarkm#else /* TCSIG */ 135857416Smarkm init_termbuf(); 135957416Smarkm *pfrontp++ = slctab[SLC_ABORT].sptr ? 136057416Smarkm (unsigned char)*slctab[SLC_ABORT].sptr : '\034'; 136157416Smarkm#endif /* TCSIG */ 136257416Smarkm} 136357416Smarkm 136457416Smarkmvoid 136557416Smarkmsendsusp() 136657416Smarkm{ 136757416Smarkm#ifdef SIGTSTP 136857416Smarkm ptyflush(); /* half-hearted */ 136957416Smarkm# ifdef TCSIG 137057416Smarkm ioctl(ourpty, TCSIG, (char *)SIGTSTP); 137157416Smarkm# else /* TCSIG */ 137257416Smarkm *pfrontp++ = slctab[SLC_SUSP].sptr ? 137357416Smarkm (unsigned char)*slctab[SLC_SUSP].sptr : '\032'; 137457416Smarkm# endif /* TCSIG */ 137557416Smarkm#endif /* SIGTSTP */ 137657416Smarkm} 137757416Smarkm 137857416Smarkm/* 137957416Smarkm * When we get an AYT, if ^T is enabled, use that. Otherwise, 138057416Smarkm * just send back "[Yes]". 138157416Smarkm */ 138257416Smarkmvoid 138357416Smarkmrecv_ayt() 138457416Smarkm{ 138557416Smarkm#if defined(SIGINFO) && defined(TCSIG) 138657416Smarkm if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) { 138757416Smarkm ioctl(ourpty, TCSIG, (char *)SIGINFO); 138857416Smarkm return; 138957416Smarkm } 139057416Smarkm#endif 139157416Smarkm output_data("\r\n[Yes]\r\n"); 139257416Smarkm} 139357416Smarkm 139457416Smarkmvoid 139557416Smarkmdoeof() 139657416Smarkm{ 139757416Smarkm init_termbuf(); 139857416Smarkm 139957416Smarkm *pfrontp++ = slctab[SLC_EOF].sptr ? 140057416Smarkm (unsigned char)*slctab[SLC_EOF].sptr : '\004'; 140157416Smarkm} 1402