openenvutils/telnetserver/src/telnetd.c
changeset 0 2e3d3ce01487
child 4 0fdb7f6b0309
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/openenvutils/telnetserver/src/telnetd.c	Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,1844 @@
+// telnetd.c
+//
+// © Portions Copyright (c) Symbian Software Ltd 2007-2008. All rights reserved.
+//
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "telnetd.h"
+
+#ifdef __SYMBIAN32__
+#include "dummy.h"
+extern void mini_inetd (int port);
+#endif
+
+#ifndef __SYMBIAN32__
+__RCSID("$Heimdal: telnetd.c,v 1.69.6.1 2004/03/22 18:17:25 lha Exp $"
+        "$NetBSD: telnetd.c,v 1.3 2004/04/02 14:59:47 lha Exp $");
+#endif
+
+#ifdef _SC_CRAY_SECURE_SYS
+#include <sys/sysv.h>
+#include <sys/secdev.h>
+#include <sys/secparm.h>
+#include <sys/usrv.h>
+int	secflag;
+char	tty_dev[16];
+struct	secdev dv;
+struct	sysv sysv;
+struct	socksec ss;
+#endif	/* _SC_CRAY_SECURE_SYS */
+
+#ifdef AUTHENTICATION
+int	auth_level = 0;
+#endif
+
+
+#ifdef __SYMBIAN32__
+#ifdef __WINSCW__
+#pragma warn_unusedarg off
+#endif
+#endif
+
+extern	int utmp_len;
+int	registerd_host_only = 0;
+
+/**moved from roken.h**/
+#define roken_getservbyname(x,y) getservbyname(x,y)
+#define roken_openlog(a,b,c) openlog(a,b,c)
+#define roken_getsockname(a,b,c) getsockname(a,b,c)
+
+#undef NOERROR
+
+#ifdef	STREAMSPTY
+# include <stropts.h>
+# include <termios.h>
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif /* HAVE_SYS_UIO_H */
+#ifdef HAVE_SYS_STREAM_H
+#include <sys/stream.h>
+#endif
+
+#ifdef _AIX
+#include <sys/termio.h>
+#endif
+# ifdef HAVE_SYS_STRTTY_H
+# include <sys/strtty.h>
+# endif
+# ifdef HAVE_SYS_STR_TTY_H
+# include <sys/str_tty.h>
+# endif
+/* make sure we don't get the bsd version */
+/* what is this here for? solaris? /joda */
+# ifdef HAVE_SYS_TTY_H
+# include "/usr/include/sys/tty.h"
+# endif
+# ifdef HAVE_SYS_PTYVAR_H
+# include <sys/ptyvar.h>
+# endif
+
+/*
+ * Because of the way ptyibuf is used with streams messages, we need
+ * ptyibuf+1 to be on a full-word boundary.  The following wierdness
+ * is simply to make that happen.
+ */
+
+long	ptyibufbuf[BUFSIZ/sizeof(long)+1];
+char	*ptyibuf = ((char *)&ptyibufbuf[1])-1;
+char	*ptyip = ((char *)&ptyibufbuf[1])-1;
+char	ptyibuf2[BUFSIZ];
+unsigned char ctlbuf[BUFSIZ];
+struct	strbuf strbufc, strbufd;
+
+int readstream(int, char*, int);
+
+#else	/* ! STREAMPTY */
+
+/*
+ * I/O data buffers,
+ * pointers, and counters.
+ */
+char	ptyibuf[BUFSIZ], *ptyip = ptyibuf;
+char	ptyibuf2[BUFSIZ];
+
+#endif /* ! STREAMPTY */
+
+int	hostinfo = 1;			/* do we print login banner? */
+
+#ifdef	_CRAY
+extern int      newmap; /* nonzero if \n maps to ^M^J */
+int	lowpty = 0, highpty;	/* low, high pty numbers */
+#endif /* CRAY */
+
+int debug = 1;
+int keepalive = 1;
+char *progname;
+
+static void usage (void);
+
+/*
+ * The string to pass to getopt().  We do it this way so
+ * that only the actual options that we support will be
+ * passed off to getopt().
+ */
+char valid_opts[] = "Bd:hklnS:u:UL:y"
+#ifdef AUTHENTICATION
+		    "a:X:z"
+#endif
+#ifdef DIAGNOSTICS
+		    "D:"
+#endif
+#ifdef _CRAY
+		    "r:"
+#endif
+		    ;
+
+static void doit(struct sockaddr*, int);
+
+#ifdef ENCRYPTION
+extern int des_check_key;
+#endif
+
+extern int getConnectionUp(void);
+
+int
+main(int argc, char **argv)
+{
+    struct sockaddr_storage __ss;
+    struct sockaddr *sa = (struct sockaddr *)&__ss;
+    int on = 1;
+    socklen_t sa_size;
+    int ch;
+#if	defined(IPPROTO_IP) && defined(IP_TOS)
+    int tos = -1;
+#endif
+#ifdef ENCRYPTION
+    des_check_key = 1;	/* Kludge for Mac NCSA telnet 2.6 /bg */
+#endif
+
+	pfrontp = pbackp = ptyobuf;
+    netip = netibuf;
+    nfrontp = nbackp = netobuf;
+	    
+#ifdef __SYMBIAN32__
+	if( getConnectionUp() < 0) exit(1);
+#endif	
+
+    setprogname(argv[0]);
+
+    progname = *argv;
+#ifdef ENCRYPTION
+    nclearto = 0;
+#endif
+
+#ifdef _CRAY
+    /*
+     * Get number of pty's before trying to process options,
+     * which may include changing pty range.
+     */
+    highpty = getnpty();
+#endif /* CRAY */
+
+    if (argc == 2 && strcmp(argv[1], "--version") == 0) {
+#ifndef __SYMBIAN32__
+	print_version(NULL); 
+#endif //__SYMBIAN32__
+	exit(0);
+    }
+
+    while ((ch = getopt(argc, argv, valid_opts)) != -1) {
+	switch(ch) {
+
+#ifdef	AUTHENTICATION
+	case 'a':
+	    /*
+	     * Check for required authentication level
+	     */
+	    if (strcmp(optarg, "debug") == 0) {
+		auth_debug_mode = 1;
+	    } else if (strcasecmp(optarg, "none") == 0) {
+		auth_level = 0;
+	    } else if (strcasecmp(optarg, "otp") == 0) {
+		auth_level = 0;
+		require_otp = 1;
+	    } else if (strcasecmp(optarg, "other") == 0) {
+		auth_level = AUTH_OTHER;
+	    } else if (strcasecmp(optarg, "user") == 0) {
+		auth_level = AUTH_USER;
+	    } else if (strcasecmp(optarg, "valid") == 0) {
+		auth_level = AUTH_VALID;
+	    } else if (strcasecmp(optarg, "off") == 0) {
+		/*
+		 * This hack turns off authentication
+		 */
+		auth_level = -1;
+	    } else {
+		fprintf(stderr,
+			"telnetd: unknown authorization level for -a\n");
+	    }
+	    break;
+#endif	/* AUTHENTICATION */
+
+	case 'B': /* BFTP mode is not supported any more */
+	    break;
+	case 'd':
+	    if (strcmp(optarg, "ebug") == 0) {
+		debug++;
+		break;
+	    }
+	    usage();
+	    /* NOTREACHED */
+	    break;
+
+#ifdef DIAGNOSTICS
+	case 'D':
+	    /*
+	     * Check for desired diagnostics capabilities.
+	     */
+	    if (!strcmp(optarg, "report")) {
+		diagnostic |= TD_REPORT|TD_OPTIONS;
+	    } else if (!strcmp(optarg, "exercise")) {
+		diagnostic |= TD_EXERCISE;
+	    } else if (!strcmp(optarg, "netdata")) {
+		diagnostic |= TD_NETDATA;
+	    } else if (!strcmp(optarg, "ptydata")) {
+		diagnostic |= TD_PTYDATA;
+	    } else if (!strcmp(optarg, "options")) {
+		diagnostic |= TD_OPTIONS;
+	    } else {
+		usage();
+		/* NOT REACHED */
+	    }
+	    break;
+#endif /* DIAGNOSTICS */
+
+
+	case 'h':
+	    hostinfo = 0;
+	    break;
+
+	case 'k': /* Linemode is not supported any more */
+	case 'l':
+	    break;
+
+	case 'n':
+	    keepalive = 0;
+	    break;
+
+#ifdef _CRAY
+	case 'r':
+	    {
+		char *strchr();
+		char *c;
+
+		/*
+		 * Allow the specification of alterations
+		 * to the pty search range.  It is legal to
+		 * specify only one, and not change the
+		 * other from its default.
+		 */
+		c = strchr(optarg, '-');
+		if (c) {
+		    *c++ = '\0';
+		    highpty = atoi(c);
+		}
+		if (*optarg != '\0')
+		    lowpty = atoi(optarg);
+		if ((lowpty > highpty) || (lowpty < 0) ||
+		    (highpty > 32767)) {
+		    usage();
+		    /* NOT REACHED */
+		}
+		break;
+	    }
+#endif	/* CRAY */
+
+	case 'S':
+#ifdef	HAVE_PARSETOS
+	    if ((tos = parsetos(optarg, "tcp")) < 0)
+		fprintf(stderr, "%s%s%s\n",
+			"telnetd: Bad TOS argument '", optarg,
+			"'; will try to use default TOS");
+#else
+	    fprintf(stderr, "%s%s\n", "TOS option unavailable; ",
+		    "-S flag not supported\n");
+#endif
+	    break;
+
+	case 'u': {
+	    char *eptr;
+
+	    utmp_len = strtol(optarg, &eptr, 0);
+	    if (optarg == eptr)
+		fprintf(stderr, "telnetd: unknown utmp len (%s)\n", optarg);
+	    break;
+	}
+
+	case 'U':
+	    registerd_host_only = 1;
+	    break;
+
+#ifdef	AUTHENTICATION
+	case 'X':
+	    /*
+	     * Check for invalid authentication types
+	     */
+	    auth_disable_name(optarg);
+	    break;
+#endif
+	case 'y':
+	    no_warn = 1;
+	    break;
+#ifdef AUTHENTICATION
+	case 'z':
+	    log_unauth = 1;
+	    break;
+
+#endif	/* AUTHENTICATION */
+
+	case 'L':
+	    new_login = optarg;
+	    break;
+			
+	default:
+	    fprintf(stderr, "telnetd: %c: unknown option\n", ch);
+	    /* FALLTHROUGH */
+	case '?':
+	    usage();
+	    /* NOTREACHED */
+	}
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    if (debug) {
+	int port = 0;
+	struct servent *sp;
+
+	if (argc > 1) {
+	    usage ();
+	} else if (argc == 1) {
+	    sp = (struct servent*)roken_getservbyname (*argv, "tcp");
+	    if (sp)
+		port = sp->s_port;
+	    else
+		port = htons(atoi(*argv));
+	} else {
+#ifdef 	__SYMBIAN32__
+		port = htons(atoi("23"));		
+#else
+#ifdef KRB5
+	    port = krb5_getportbyname (NULL, "telnet", "tcp", 23);
+#else
+	    port = k_getportbyname("telnet", "tcp", htons(23));
+#endif
+#endif //__SYMBIAN32__
+	}
+	mini_inetd (port);
+    } else if (argc > 0) {
+	usage();
+	/* NOT REACHED */
+    }
+
+#ifdef _SC_CRAY_SECURE_SYS
+    secflag = sysconf(_SC_CRAY_SECURE_SYS);
+
+    /*
+     *	Get socket's security label
+     */
+    if (secflag)  {
+	socklen_t szss = sizeof(ss);
+	int sock_multi;
+	socklen_t szi = sizeof(int);
+
+	memset(&dv, 0, sizeof(dv));
+
+	if (getsysv(&sysv, sizeof(struct sysv)) != 0) 
+	    fatalperror(net, "getsysv");
+
+	/*
+	 *	Get socket security label and set device values
+	 *	   {security label to be set on ttyp device}
+	 */
+#ifdef SO_SEC_MULTI			/* 8.0 code */
+	if ((getsockopt(0, SOL_SOCKET, SO_SECURITY,
+			(void *)&ss, &szss) < 0) ||
+	    (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI,
+			(void *)&sock_multi, &szi) < 0)) 
+	    fatalperror(net, "getsockopt");
+	else {
+	    dv.dv_actlvl = ss.ss_actlabel.lt_level;
+	    dv.dv_actcmp = ss.ss_actlabel.lt_compart;
+	    if (!sock_multi) {
+		dv.dv_minlvl = dv.dv_maxlvl = dv.dv_actlvl;
+		dv.dv_valcmp = dv.dv_actcmp;
+	    } else {
+		dv.dv_minlvl = ss.ss_minlabel.lt_level;
+		dv.dv_maxlvl = ss.ss_maxlabel.lt_level;
+		dv.dv_valcmp = ss.ss_maxlabel.lt_compart;
+	    }
+	    dv.dv_devflg = 0;
+	}
+#else /* SO_SEC_MULTI */		/* 7.0 code */
+	if (getsockopt(0, SOL_SOCKET, SO_SECURITY,
+		       (void *)&ss, &szss) >= 0) {
+	    dv.dv_actlvl = ss.ss_slevel;
+	    dv.dv_actcmp = ss.ss_compart;
+	    dv.dv_minlvl = ss.ss_minlvl;
+	    dv.dv_maxlvl = ss.ss_maxlvl;
+	    dv.dv_valcmp = ss.ss_maxcmp;
+	}
+#endif /* SO_SEC_MULTI */
+    }
+#endif	/* _SC_CRAY_SECURE_SYS */
+
+ 
+    roken_openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
+    sa_size = sizeof (__ss);
+    
+    if (getpeername(STDIN_FILENO, sa, &sa_size) < 0) {
+	fprintf(stderr, "%s: ", progname);
+	perror("getpeername");
+	_exit(1);
+    }
+
+    if (keepalive &&
+	setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE,
+		   (void *)&on, sizeof (on)) < 0) {		 
+#ifndef __SYMBIAN32__		     
+	syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+#endif
+	;
+    }
+    
+
+#if	defined(IPPROTO_IP) && defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
+    {
+# ifdef HAVE_GETTOSBYNAME
+	struct tosent *tp;
+	if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
+	    tos = tp->t_tos;
+# endif
+	if (tos < 0)
+	    tos = 020;	/* Low Delay bit */
+	if (tos
+	    && sa->sa_family == AF_INET
+	    && (setsockopt(STDIN_FILENO, IPPROTO_IP, IP_TOS,
+			   (void *)&tos, sizeof(tos)) < 0)
+	    && (errno != ENOPROTOOPT) )
+	    syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+    }
+#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
+    net = STDIN_FILENO;
+    doit(sa, sa_size);
+    /* NOTREACHED */
+    return 0;
+}  /* end of main */
+
+static void
+usage(void)
+{
+    fprintf(stderr, "Usage: telnetd");
+#ifdef	AUTHENTICATION
+    fprintf(stderr, " [-a (debug|other|otp|user|valid|off|none)]\n\t");
+#endif
+    fprintf(stderr, " [-debug]");
+#ifdef DIAGNOSTICS
+    fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
+#endif
+#ifdef	AUTHENTICATION
+    fprintf(stderr, " [-edebug]");
+#endif
+    fprintf(stderr, " [-h]");
+    fprintf(stderr, " [-L login]");
+    fprintf(stderr, " [-n]");
+#ifdef	_CRAY
+    fprintf(stderr, " [-r[lowpty]-[highpty]]");
+#endif
+    fprintf(stderr, "\n\t");
+#ifdef	HAVE_GETTOSBYNAME
+    fprintf(stderr, " [-S tos]");
+#endif
+#ifdef	AUTHENTICATION
+    fprintf(stderr, " [-X auth-type] [-y] [-z]");
+#endif
+    fprintf(stderr, " [-u utmp_hostname_length] [-U]");
+    fprintf(stderr, " [port]\n");
+    exit(1);
+}
+
+/*
+ * getterminaltype
+ *
+ *	Ask the other end to send along its terminal type and speed.
+ * Output is the variable terminaltype filled in.
+ */
+static unsigned char ttytype_sbbuf[] = {
+    IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE
+};
+
+int
+getterminaltype(char *name, size_t name_sz)
+{
+    int retval = -1;
+
+    settimer(baseline);
+#ifdef AUTHENTICATION
+    /*
+     * Handle the Authentication option before we do anything else.
+     */
+    send_do(TELOPT_AUTHENTICATION, 1);
+    while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
+	ttloop();
+    if (his_state_is_will(TELOPT_AUTHENTICATION)) {
+	retval = auth_wait(name, name_sz);
+    }
+#endif
+
+#ifdef ENCRYPTION
+    send_will(TELOPT_ENCRYPT, 1);
+    send_do(TELOPT_ENCRYPT, 1);	/* esc@magic.fi */
+#endif
+    send_do(TELOPT_TTYPE, 1);
+    send_do(TELOPT_TSPEED, 1);
+    send_do(TELOPT_XDISPLOC, 1);
+    send_do(TELOPT_NEW_ENVIRON, 1);
+    send_do(TELOPT_OLD_ENVIRON, 1);
+    while (
+#ifdef ENCRYPTION
+	   his_do_dont_is_changing(TELOPT_ENCRYPT) ||
+#endif
+	   his_will_wont_is_changing(TELOPT_TTYPE) ||
+	   his_will_wont_is_changing(TELOPT_TSPEED) ||
+	   his_will_wont_is_changing(TELOPT_XDISPLOC) ||
+	   his_will_wont_is_changing(TELOPT_NEW_ENVIRON) ||
+	   his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) {
+	ttloop();
+    }
+#ifdef ENCRYPTION
+    /*
+     * Wait for the negotiation of what type of encryption we can
+     * send with.  If autoencrypt is not set, this will just return.
+     */
+    if (his_state_is_will(TELOPT_ENCRYPT)) {
+	encrypt_wait();
+    }
+#endif
+    if (his_state_is_will(TELOPT_TSPEED)) {
+	static unsigned char sb[] =
+	{ IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
+
+	telnet_net_write (sb, sizeof sb);
+	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+    }
+    if (his_state_is_will(TELOPT_XDISPLOC)) {
+	static unsigned char sb[] =
+	{ IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
+
+	telnet_net_write (sb, sizeof sb);
+	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+    }
+    if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
+	static unsigned char sb[] =
+	{ IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE };
+
+	telnet_net_write (sb, sizeof sb);
+	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+    }
+    else if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
+	static unsigned char sb[] =
+	{ IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE };
+
+	telnet_net_write (sb, sizeof sb);
+	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+    }
+    if (his_state_is_will(TELOPT_TTYPE)) {
+
+	telnet_net_write (ttytype_sbbuf, sizeof ttytype_sbbuf);
+	DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
+				  sizeof ttytype_sbbuf - 2););
+    }
+    if (his_state_is_will(TELOPT_TSPEED)) {
+	while (sequenceIs(tspeedsubopt, baseline))
+	    ttloop();
+    }
+    if (his_state_is_will(TELOPT_XDISPLOC)) {
+	while (sequenceIs(xdisplocsubopt, baseline))
+	    ttloop();
+    }
+    if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
+	while (sequenceIs(environsubopt, baseline))
+	    ttloop();
+    }
+    if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
+	while (sequenceIs(oenvironsubopt, baseline))
+	    ttloop();
+    }
+    if (his_state_is_will(TELOPT_TTYPE)) {
+	char first[256], last[256];
+
+	while (sequenceIs(ttypesubopt, baseline))
+	    ttloop();
+
+	/*
+	 * If the other side has already disabled the option, then
+	 * we have to just go with what we (might) have already gotten.
+	 */
+	if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
+	    strlcpy(first, terminaltype, sizeof(first));
+	    for(;;) {
+		/*
+		 * Save the unknown name, and request the next name.
+		 */
+		strlcpy(last, terminaltype, sizeof(last));
+		_gettermname();
+		if (terminaltypeok(terminaltype))
+		    break;
+		if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
+		    his_state_is_wont(TELOPT_TTYPE)) {
+		    /*
+		     * We've hit the end.  If this is the same as
+		     * the first name, just go with it.
+		     */
+		    if (strncmp(first, terminaltype, sizeof(first)) == 0)
+			break;
+		    /*
+		     * Get the terminal name one more time, so that
+		     * RFC1091 compliant telnets will cycle back to
+		     * the start of the list.
+		     */
+		    _gettermname();
+		    if (strncmp(first, terminaltype, sizeof(first)) != 0)
+			strcpy(terminaltype, first);
+		    break;
+		}
+	    }
+	}
+    }
+    return(retval);
+}  /* end of getterminaltype */
+
+void
+_gettermname(void)
+{
+    /*
+     * If the client turned off the option,
+     * we can't send another request, so we
+     * just return.
+     */
+    if (his_state_is_wont(TELOPT_TTYPE))
+	return;
+    settimer(baseline);
+    telnet_net_write (ttytype_sbbuf, sizeof ttytype_sbbuf);
+    DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
+			      sizeof ttytype_sbbuf - 2););
+    while (sequenceIs(ttypesubopt, baseline))
+	ttloop();
+}
+
+int
+terminaltypeok(char *s)
+{
+    return 1;
+}
+
+
+char host_name[MAXHOSTNAMELEN];
+char remote_host_name[MAXHOSTNAMELEN];
+char remote_utmp_name[MAXHOSTNAMELEN];
+
+static int
+getnameinfo_verified(const struct sockaddr *sa, socklen_t salen,
+		     char *host, size_t hostlen,
+		     char *serv, size_t servlen,
+		     int flags)
+{
+    int ret;
+    struct addrinfo *ai, *a;
+    char servbuf[NI_MAXSERV];
+    struct addrinfo hints;
+
+    if (host == NULL)
+	return EAI_NONAME;
+
+    if (serv == NULL) {
+	serv = servbuf;
+	servlen = sizeof(servbuf);
+    }
+
+    ret = getnameinfo (sa, salen, host, hostlen, serv, servlen,
+		       flags | NI_NUMERICSERV);
+    if (ret)
+	goto fail;
+
+    memset (&hints, 0, sizeof(hints));
+    hints.ai_socktype = SOCK_STREAM;
+    ret = getaddrinfo (host, serv, &hints, &ai);
+    if (ret)
+	goto fail;
+    for (a = ai; a != NULL; a = a->ai_next) {
+	if (a->ai_addrlen == salen
+	    && memcmp (a->ai_addr, sa, salen) == 0) {
+	    freeaddrinfo (ai);
+	    return 0;
+	}
+    }
+    freeaddrinfo (ai);
+ fail:
+    if (flags & NI_NAMEREQD)
+	return EAI_NONAME;
+    ret = getnameinfo (sa, salen, host, hostlen, serv, servlen,
+		       flags | NI_NUMERICSERV | NI_NUMERICHOST);
+    return ret;
+}
+
+#ifdef __SYMBIAN32__
+//replace the ocurrences of \n with \n\r.
+//caller should free the memory
+char* add_return(char* source)
+	{
+	int occur=0, len=0, tokens=0, occurbk=0;
+	char *token, *ret; 
+	
+	if(NULL==source || !(len=strlen(source)))
+		return NULL;
+
+	ret=(char*)calloc(len+1, sizeof(char));	
+	strcpy(ret, source);
+	
+	
+	occur=source[len-1]=='\n'? 1:0;
+	if(len>1 && source[0]=='\n')
+		occur+=1;
+		
+	//find the no. of occurrences of \n
+	token=strtok(source, "\n");
+	while(token)
+		{	
+		token=strtok(NULL, "\n");				
+		tokens++;
+		}
+
+	occurbk=occur=tokens>1?tokens+occur-1: occur;
+	if(occur<=0)
+		{
+		return ret;
+		}		
+	
+	//start replacing with \n\r	
+	
+	/* start moving from end of the string. 
+	 * If the no. of occurences of \n is n(n set), then move the nth set
+	 * to n bytes forward and n-1th set to n-1 bytes forward and similarly 
+	 * for the rest until it reaches the first set.
+ 	 */	
+	ret=(char*)realloc(ret, (sizeof(char)*(len+occur+1)));
+	if(ret)
+		{
+		
+		int counter=len-1;
+		while(occur>0 && counter>0)
+			{
+			while(ret[counter]!='\n')
+				{
+				ret[counter+occur]=ret[counter];
+				counter--;								
+				}
+			ret[counter+occur-1]='\n';					
+			ret[counter+occur]='\r';	
+			counter--;
+			occur--;				
+			}
+		ret[len+occurbk]='\0'; //terminate the entire string	
+		}		
+	return ret;		
+	}
+	
+	
+void readinput(char* line_o, int* length, int size)								
+{
+	char read_c;
+	if(!line_o || !length)
+		return;
+		
+	*length=0;
+	read(net, &read_c, 1);																			
+	while(read_c!='\n')	//read the command from client		
+		{						
+		if(*length==size-1)
+			break;						
+		
+		if(read_c=='\r')
+			{
+			read(net, &read_c, 1);
+			line_o[(*length)++]='\n';
+			break;
+			}
+		write(net, &read_c, 1);	
+		line_o[(*length)++]=read_c;
+		read(net, &read_c, 1);
+		}
+		
+	line_o[*length]='\0';
+}
+#endif
+
+/*
+ * Get a pty, scan input lines.
+ */
+static void
+doit(struct sockaddr *who, int who_len)
+{
+#ifndef __SYMBIAN32__     
+    int level;
+    int ptynum;
+    int error;
+    char user_name[256];        
+    /*
+     * Find an available pty to use.
+     */
+    ourpty = getpty(&ptynum);
+    if (ourpty < 0)
+	fatal(net, "All network ports in use");
+
+#ifdef _SC_CRAY_SECURE_SYS
+    /*
+     *	set ttyp line security label
+     */
+    if (secflag) {
+	char slave_dev[16];
+
+	snprintf(tty_dev, sizeof(tty_dev), "/dev/pty/%03d", ptynum);
+	if (setdevs(tty_dev, &dv) < 0)
+	    fatal(net, "cannot set pty security");
+	snprintf(slave_dev, sizeof(slave_dev), "/dev/ttyp%03d", ptynum);
+	if (setdevs(slave_dev, &dv) < 0)
+	    fatal(net, "cannot set tty security");
+    }
+#endif	/* _SC_CRAY_SECURE_SYS */
+    error = getnameinfo_verified (who, who_len,
+				  remote_host_name,
+				  sizeof(remote_host_name),
+				  NULL, 0, 
+				  registerd_host_only ? NI_NAMEREQD : 0);
+    if (error)
+	fatal(net, "Couldn't resolve your address into a host name.\r\n\
+Please contact your net administrator");
+
+    gethostname(host_name, sizeof (host_name));
+
+    strlcpy (remote_utmp_name, remote_host_name, sizeof(remote_utmp_name));
+
+    /* Only trim if too long (and possible) */
+    if (strlen(remote_utmp_name) > utmp_len) {
+	char *domain = strchr(host_name, '.');
+	char *p = strchr(remote_utmp_name, '.');
+	if (domain != NULL && p != NULL && (strcmp(p, domain) == 0))
+	    *p = '\0'; /* remove domain part */
+    }
+
+    /*
+     * If hostname still doesn't fit utmp, use ipaddr.
+     */
+    if (strlen(remote_utmp_name) > utmp_len) {
+	error = getnameinfo (who, who_len,
+			     remote_utmp_name,
+			     sizeof(remote_utmp_name),
+			     NULL, 0,
+			     NI_NUMERICHOST);
+	if (error)
+	    fatal(net, "Couldn't get numeric address\r\n");
+    }
+
+#ifdef AUTHENTICATION
+    auth_encrypt_init(host_name, remote_host_name, "TELNETD", 1);
+#endif
+
+    init_env();
+    /*
+     * get terminal type.
+     */
+    *user_name = 0;
+    level = getterminaltype(user_name, sizeof(user_name));
+    setenv("TERM", terminaltype ? terminaltype : "network", 1);
+
+#ifdef _SC_CRAY_SECURE_SYS
+    if (secflag) {
+	if (setulvl(dv.dv_actlvl) < 0)
+	    fatal(net,"cannot setulvl()");
+	if (setucmp(dv.dv_actcmp) < 0)
+	    fatal(net, "cannot setucmp()");
+    }
+#endif	/* _SC_CRAY_SECURE_SYS */
+#endif //__SYMBIAN32__
+    /* begin server processing */
+    my_telnet();	      
+	      
+    /*NOTREACHED*/
+}  /* end of doit */
+
+#ifdef __SYMBIAN32__
+
+#define PASSKEY_MAXLEN 8
+
+static
+int clientAuthentication(char* dev_key)
+{
+
+	char* get_key="Enter Key: ";
+	fd_set read_fds;    		    	
+    struct timeval tv;
+  	char client_buf[PASSKEY_MAXLEN+1];  
+  	char read_c;
+	int buf_len=0;
+		
+    if(dev_key==NULL)
+    	return 1;
+    
+	write(net, get_key, strlen(get_key));
+    FD_ZERO(&read_fds);
+	FD_SET(net, &read_fds); 	
+
+	tv.tv_sec = 60;
+	tv.tv_usec = 0;  
+
+	//exit if nothing is read for 60 secs
+	if(select(net+1, &read_fds, NULL, NULL, &tv)==0)
+		{
+		char* login_timout="Authentication Failure:\
+			 	timeout\n";
+			 	
+		write(1, login_timout, strlen(login_timout));
+		exit(1);
+		}
+	
+	if(FD_ISSET(net, &read_fds))
+		{
+		while(buf_len < PASSKEY_MAXLEN)
+			{
+			read(net, &read_c, 1); //read from socket fd
+			switch(read_c)
+				{
+				case '\n':
+					goto jump_out; 
+				
+				case '\b':
+					//ignore previous character.
+					write(net, "\b", 1);
+					if(buf_len > 0)
+						buf_len--;
+					
+				case '\r':
+					break;
+					
+				default:
+					//let all other keys be part of the passkey.
+					write(net, "*", 1);
+					client_buf[buf_len++]=read_c;										
+					break;
+				}
+			}
+		
+jump_out:
+		//pass key max length has reached or '\r\n' is entered.
+		write(net, "\r\n", 2); 
+		client_buf[buf_len]='\0';
+		}
+		
+	if(strcmp(dev_key, client_buf)==0)
+		return 0;
+	
+	return 1;
+}
+
+static char key[PASSKEY_MAXLEN+1];
+char* deviceAuthentication()
+	{
+	fd_set read_fds;    		    	
+    struct timeval tv;
+	int console_fd=open("CON:", O_RDWR);
+	const char* login_key="Enter Key: ";
+    
+    FD_ZERO(&read_fds);
+	FD_SET(console_fd, &read_fds); 			
+	
+	if(console_fd!=-1)
+		{
+		write(console_fd, login_key, strlen(login_key));
+
+		tv.tv_sec = 60;
+		tv.tv_usec = 0;  
+
+		//exit if nothing is read for 60 secs
+		if(select(console_fd+1, &read_fds, NULL, NULL, &tv)==0)
+			{
+			char* login_timout="Authentication Failure:\
+				 	timeout\n";
+				 	
+			write(1, login_timout, strlen(login_timout));
+			exit(1);
+			}
+			
+		if(FD_ISSET(console_fd, &read_fds))
+			{
+			char read_c;
+			int buf_len=0;
+			char key_buf[PASSKEY_MAXLEN+1];
+		
+			setecho(console_fd, '*');  //turn off the echo
+			while(buf_len < PASSKEY_MAXLEN)
+				{
+				read(console_fd, &read_c, 1);				
+				switch(read_c)
+					{
+					case '\n':
+						if(buf_len==0)
+							continue;
+						else
+							goto jump_out;
+					
+					case '\b':
+						//ignore previous character...
+						if(buf_len > 0)
+							buf_len--;
+						break;
+					
+					default:
+						//let all other keys be part of the passkey...
+						key_buf[buf_len++]=read_c;										
+						break;
+					}
+				}
+		
+jump_out:		
+			setecho(console_fd, 1); //turn on the echo
+			key_buf[buf_len]='\0';		
+			
+			if(buf_len > 0 && buf_len <= PASSKEY_MAXLEN)
+				strcpy(key, key_buf);	
+			
+			close(console_fd);
+			return key;
+			}
+		}
+	else			
+		{
+		char* console_err="Authentication Failure:\
+				 	console not supported\n";
+				 	
+		write(1, console_err, strlen(console_err));
+		exit(1);
+		}
+	
+	return NULL;	
+	}
+
+#endif	
+/* output contents of /etc/issue.net, or /etc/issue */
+#ifndef __SYMBIAN32__
+static void
+show_issue(void)
+{
+    FILE *f;
+    char buf[128];
+    f = fopen(SYSCONFDIR "/issue.net", "r");
+    if(f == NULL)
+	f = fopen(SYSCONFDIR "/issue", "r");
+    if(f){
+	while(fgets(buf, sizeof(buf)-2, f)){
+	    strcpy(buf + strcspn(buf, "\r\n"), "\r\n");
+	    writenet((unsigned char*)buf, strlen(buf));
+	}
+	fclose(f);
+    }
+}
+#endif //__SYMBIAN32__
+/*
+ * Main loop.  Select from pty and network, and
+ * hand data to telnet receiver finite state machine.
+ */
+void
+my_telnet()
+{
+    int on = 1;
+#ifndef __SYMBIAN32__    
+    char *he;
+    char *IM;
+    int nfd;
+    time_t timeout;
+#endif    
+    int startslave_called = 0;
+    int fds[3],pid; 
+           
+    /*
+     * Initialize the slc mapping table.
+     */
+    get_slc_defaults();
+
+    /*
+     * Do some tests where it is desireable to wait for a response.
+     * Rather than doing them slowly, one at a time, do them all
+     * at once.
+     */
+    if (my_state_is_wont(TELOPT_SGA))
+		send_will(TELOPT_SGA, 1);
+    /*
+     * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
+     * because 4.2 clients are unable to deal with TCP urgent data.
+     *
+     * To find out, we send out a "DO ECHO".  If the remote system
+     * answers "WILL ECHO" it is probably a 4.2 client, and we note
+     * that fact ("WILL ECHO" ==> that the client will echo what
+     * WE, the server, sends it; it does NOT mean that the client will
+     * echo the terminal input).
+     */
+    send_do(TELOPT_ECHO, 1);
+    
+#ifdef __SYMBIAN32__
+    if (my_state_is_wont(TELOPT_ECHO))
+    	send_will(TELOPT_ECHO, 1);
+#endif  
+  
+    /*
+     * Send along a couple of other options that we wish to negotiate.
+     */
+    send_do(TELOPT_NAWS, 1);
+    send_will(TELOPT_STATUS, 1);
+    flowmode = 1;		/* default flow control state */
+    restartany = -1;	/* uninitialized... */
+    send_do(TELOPT_LFLOW, 1);
+
+    /*
+     * Spin, waiting for a response from the DO ECHO.  However,
+     * some REALLY DUMB telnets out there might not respond
+     * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
+     * telnets so far seem to respond with WONT for a DO that
+     * they don't understand...) because by the time we get the
+     * response, it will already have processed the DO ECHO.
+     * Kludge upon kludge.
+     */
+    while (his_will_wont_is_changing(TELOPT_NAWS))
+	ttloop();
+
+    /*
+     * But...
+     * The client might have sent a WILL NAWS as part of its
+     * startup code; if so, we'll be here before we get the
+     * response to the DO ECHO.  We'll make the assumption
+     * that any implementation that understands about NAWS
+     * is a modern enough implementation that it will respond
+     * to our DO ECHO request; hence we'll do another spin
+     * waiting for the ECHO option to settle down, which is
+     * what we wanted to do in the first place...
+     */
+    if (his_want_state_is_will(TELOPT_ECHO) &&
+	his_state_is_will(TELOPT_NAWS)) {
+	while (his_will_wont_is_changing(TELOPT_ECHO))
+	    ttloop();
+    }
+    /*
+     * On the off chance that the telnet client is broken and does not
+     * respond to the DO ECHO we sent, (after all, we did send the
+     * DO NAWS negotiation after the DO ECHO, and we won't get here
+     * until a response to the DO NAWS comes back) simulate the
+     * receipt of a will echo.  This will also send a WONT ECHO
+     * to the client, since we assume that the client failed to
+     * respond because it believes that it is already in DO ECHO
+     * mode, which we do not want.
+     */
+    if (his_want_state_is_will(TELOPT_ECHO)) {
+	DIAG(TD_OPTIONS,
+	     {output_data("td: simulating recv\r\n");
+	     });
+	willoption(TELOPT_ECHO);
+    }
+
+    /*
+     * Finally, to clean things up, we turn on our echo.  This
+     * will break stupid 4.2 telnets out of local terminal echo.
+     */
+     
+	if (my_state_is_wont(TELOPT_ECHO))
+	send_will(TELOPT_ECHO, 1);
+    
+#ifndef __SYMBIAN32__ //below are not required...
+
+#ifdef TIOCPKT
+#ifdef	STREAMSPTY
+    if (!really_stream)
+#endif
+	/*
+	 * Turn on packet mode
+	 */
+	ioctl(p, TIOCPKT, (char *)&on);
+#endif
+
+
+    /*
+     * Call telrcv() once to pick up anything received during
+     * terminal type negotiation, 4.2/4.3 determination, and
+     * linemode negotiation.
+     */
+    telrcv();
+
+    ioctl(f, FIONBIO, (char *)&on);
+    ioctl(p, FIONBIO, (char *)&on);
+
+#if	defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT)
+    setsockopt(net, SOL_SOCKET, SO_OOBINLINE,
+	       (void *)&on, sizeof on);
+#endif	/* defined(SO_OOBINLINE) */
+
+#ifdef	SIGTSTP
+#ifndef __SYMBIAN32__
+    signal(SIGTSTP, SIG_IGN);
+#endif    
+#endif
+#ifdef	SIGTTOU
+    /*
+     * Ignoring SIGTTOU keeps the kernel from blocking us
+     * in ttioct() in /sys/tty.c.
+     */
+#ifndef __SYMBIAN32__     
+    signal(SIGTTOU, SIG_IGN);
+#endif    
+#endif
+
+#ifndef __SYMBIAN32__
+    signal(SIGCHLD, cleanup);
+#endif    
+
+#ifdef  TIOCNOTTY
+    {
+	int t;
+	t = open(_PATH_TTY, O_RDWR);
+	if (t >= 0) {
+	    ioctl(t, TIOCNOTTY, (char *)0);
+	    close(t);
+	}
+    }
+#endif
+
+    show_issue();
+
+
+    /*
+     * Show banner that getty never gave.
+     *
+     * We put the banner in the pty input buffer.  This way, it
+     * gets carriage return null processing, etc., just like all
+     * other pty --> client data.
+     */
+
+    if (getenv("USER"))
+	hostinfo = 0;
+
+    IM = DEFAULT_IM;
+    he = 0;
+    edithost(he, host_name);
+    if (hostinfo && *IM)
+	putf(IM, ptyibuf2);
+
+    if (pcc)
+	strncat(ptyibuf2, ptyip, pcc+1);
+    ptyip = ptyibuf2;
+    pcc = strlen(ptyip);
+
+    DIAG(TD_REPORT, {
+	output_data("td: Entering processing loop\r\n");
+    });
+
+
+    nfd = ((f > p) ? f : p) + 1;
+    timeout = time(NULL) + 5;
+
+    for (;;) {
+	fd_set ibits, obits, xbits;
+	int c;
+	/* wait for encryption to be turned on, but don't wait
+           indefinitely */
+#ifndef __SYMBIAN32__           
+	if(!startslave_called && (/*!encrypt_delay() || */timeout > time(NULL))){
+	
+	    startslave_called = 1;	    
+	    startslave(host, utmp_host, level, autoname);
+	}
+#endif
+
+	if (ncc < 0 && pcc < 0)
+	    break;
+
+	FD_ZERO(&ibits);
+	FD_ZERO(&obits);
+	FD_ZERO(&xbits);
+
+	if (f >= FD_SETSIZE
+	    || p >= FD_SETSIZE)
+	    fatal(net, "fd too large");
+
+	/*
+	 * Never look for input if there's still
+	 * stuff in the corresponding output buffer
+	 */
+	if (nfrontp - nbackp || pcc > 0) {
+	    FD_SET(f, &obits);
+	} else {
+	    FD_SET(p, &ibits);
+	}
+	if (pfrontp - pbackp || ncc > 0) {
+	    FD_SET(p, &obits);
+	} else {
+	    FD_SET(f, &ibits);
+	}
+	if (!SYNCHing) {
+	    FD_SET(f, &xbits);
+	}
+	if ((c = select(nfd, &ibits, &obits, &xbits,
+			(struct timeval *)0)) < 1) {
+	    if (c == -1) {
+		if (errno == EINTR) {
+		    continue;
+		}
+	    }
+	    sleep(5);
+	    continue;
+	}
+
+	/*
+	 * Any urgent data?
+	 */
+	if (FD_ISSET(net, &xbits)) {
+	    SYNCHing = 1;
+	}
+
+	/*
+	 * Something to read from the network...
+	 */
+	if (FD_ISSET(net, &ibits)) {
+#ifndef SO_OOBINLINE
+	    /*
+	     * In 4.2 (and 4.3 beta) systems, the
+	     * OOB indication and data handling in the kernel
+	     * is such that if two separate TCP Urgent requests
+	     * come in, one byte of TCP data will be overlaid.
+	     * This is fatal for Telnet, but we try to live
+	     * with it.
+	     *
+	     * In addition, in 4.2 (and...), a special protocol
+	     * is needed to pick up the TCP Urgent data in
+	     * the correct sequence.
+	     *
+	     * What we do is:  if we think we are in urgent
+	     * mode, we look to see if we are "at the mark".
+	     * If we are, we do an OOB receive.  If we run
+	     * this twice, we will do the OOB receive twice,
+	     * but the second will fail, since the second
+	     * time we were "at the mark", but there wasn't
+	     * any data there (the kernel doesn't reset
+	     * "at the mark" until we do a normal read).
+	     * Once we've read the OOB data, we go ahead
+	     * and do normal reads.
+	     *
+	     * There is also another problem, which is that
+	     * since the OOB byte we read doesn't put us
+	     * out of OOB state, and since that byte is most
+	     * likely the TELNET DM (data mark), we would
+	     * stay in the TELNET SYNCH (SYNCHing) state.
+	     * So, clocks to the rescue.  If we've "just"
+	     * received a DM, then we test for the
+	     * presence of OOB data when the receive OOB
+	     * fails (and AFTER we did the normal mode read
+	     * to clear "at the mark").
+	     */
+	    if (SYNCHing) {
+		int atmark;
+
+		ioctl(net, SIOCATMARK, (char *)&atmark);
+		if (atmark) {
+		    ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
+		    if ((ncc == -1) && (errno == EINVAL)) {
+			ncc = read(net, netibuf, sizeof (netibuf));
+			if (sequenceIs(didnetreceive, gotDM)) {
+			    SYNCHing = stilloob(net);
+			}
+		    }
+		} else {
+		    ncc = read(net, netibuf, sizeof (netibuf));
+		}
+	    } else {
+		ncc = read(net, netibuf, sizeof (netibuf));
+	    }
+	    settimer(didnetreceive);
+#else	/* !defined(SO_OOBINLINE)) */
+	    ncc = read(net, netibuf, sizeof (netibuf));
+#endif	/* !defined(SO_OOBINLINE)) */
+	    if (ncc < 0 && errno == EWOULDBLOCK)
+		ncc = 0;
+	    else {
+		if (ncc <= 0) {
+		    break;
+		}
+		netip = netibuf;
+	    }
+	    DIAG((TD_REPORT | TD_NETDATA), {
+		output_data("td: netread %d chars\r\n", ncc);
+		});
+	    DIAG(TD_NETDATA, printdata("nd", netip, ncc));
+	}
+
+	/*
+	 * Something to read from the pty...
+	 */
+	if (FD_ISSET(p, &ibits)) {
+#ifdef STREAMSPTY
+	    if (really_stream)
+		pcc = readstream(p, ptyibuf, BUFSIZ);
+	    else
+#endif
+		pcc = read(p, ptyibuf, BUFSIZ);
+
+	    /*
+	     * On some systems, if we try to read something
+	     * off the master side before the slave side is
+	     * opened, we get EIO.
+	     */
+	    if (pcc < 0 && (errno == EWOULDBLOCK ||
+#ifdef	EAGAIN
+			    errno == EAGAIN ||
+#endif
+			    errno == EIO)) {
+		pcc = 0;
+	    } else {
+		if (pcc <= 0)
+		    break;
+		if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
+		    netclear();	/* clear buffer back */
+#ifndef	NO_URGENT
+		    /*
+		     * There are client telnets on some
+		     * operating systems get screwed up
+		     * royally if we send them urgent
+		     * mode data.
+		     */
+		    output_data ("%c%c", IAC, DM);
+
+		    neturg = nfrontp-1; /* off by one XXX */
+		    DIAG(TD_OPTIONS,
+			 printoption("td: send IAC", DM));
+
+#endif
+		}
+		if (his_state_is_will(TELOPT_LFLOW) &&
+		    (ptyibuf[0] &
+		     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
+		    int newflow =
+			ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
+		    if (newflow != flowmode) {
+			flowmode = newflow;
+			output_data("%c%c%c%c%c%c",
+				    IAC, SB, TELOPT_LFLOW,
+				    flowmode ? LFLOW_ON
+				    : LFLOW_OFF,
+				    IAC, SE);
+			DIAG(TD_OPTIONS, printsub('>',
+						  (unsigned char *)nfrontp-4,
+						  4););
+		    }
+		}
+		pcc--;
+		ptyip = ptyibuf+1;
+	    }
+	}
+
+	while (pcc > 0) {
+	    if ((&netobuf[BUFSIZ] - nfrontp) < 3)
+		break;
+	    c = *ptyip++ & 0377, pcc--;
+	    if (c == IAC)
+		*nfrontp++ = c;
+	    *nfrontp++ = c;
+	    if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
+		if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
+		    *nfrontp++ = *ptyip++ & 0377;
+		    pcc--;
+		} else
+		    *nfrontp++ = '\0';
+	    }
+	}
+
+	if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
+	    netflush();
+	if (ncc > 0)
+	    telrcv();
+	if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
+	    ptyflush();
+    }
+#else 	
+	
+	//authenticate the user
+	if( clientAuthentication(deviceAuthentication()) )
+		{
+		char* auth_err="Authentication Error\n";
+		write(net, auth_err, strlen(auth_err));
+		exit(1);	
+		}
+		
+	//launch shell and redirect the commands...	
+	pid=popen3("zsh.exe", NULL, NULL, fds);
+	if(pid>0)
+		{
+		char read_zsh[256];
+		int sock_cnt=0, zsh_cnt=0, ret;
+		int max;
+	    fd_set read_fds;    
+		max= MAX(net, MAX(fds[1], fds[2]));		
+		for(;;)
+			{		    						
+			int status=-1;		    						
+			FD_ZERO(&read_fds);
+			FD_SET(net, &read_fds); 
+			FD_SET(fds[1], &read_fds); 	  
+			FD_SET(fds[2], &read_fds); 	  			
+			
+			//is child terminated...
+			if(pid == waitpid(pid, &status, WNOHANG)) 
+				{
+				close(net);
+				exit(1);//exit server here...	
+				}
+				
+			//is any of the fds ready for read...
+			ret=select(max+1, &read_fds, NULL, NULL, NULL);
+			if(ret<0)
+				break;
+					
+			//is there any data to be written on to pipe				
+			if(FD_ISSET(net, &read_fds))
+				{
+				char temp;
+				sock_cnt=0;
+				
+				sock_cnt=read(net, &temp, 1);
+				if(sock_cnt > 0)
+					{
+					//echo the command..
+					write(net, &temp, 1);	
+					if(temp =='\r')
+						{
+						sock_cnt=read(net, &temp, 1); //expect \n here...
+						write(net, &temp, 1);
+						if(sock_cnt && !(write(fds[0], &temp, 1) > 0))	
+							printf("telnetd: zsh is not waiting for data.\n");
+						}
+					else
+						{
+						if(!(write(fds[0], &temp, 1) > 0))	
+							printf("telnetd: zsh is not waiting for data.\n");
+						}
+					}
+   		    	}	
+   		    
+   		    //is there any data to be written onto socket..			
+			if(FD_ISSET(fds[1], &read_fds))
+				{
+				memset(&read_zsh[0], 0, 256);				
+				
+				zsh_cnt=read(fds[1], &read_zsh[0], 255);
+				if(zsh_cnt>0)
+					{
+					char* write_net;
+					//reading from the socket can have more than one \n
+					//so replace all \n with \r\n.					
+					write_net=add_return(read_zsh);
+					if(write_net)
+						{
+						write(net, write_net, strlen(write_net));							
+						free(write_net);
+						}
+					}					
+				}	
+				   		    
+   		    //is there any data to be written onto socket..			
+			if (FD_ISSET(fds[2], &read_fds))	
+				{
+				memset(&read_zsh[0], 0, 256);				
+				
+				zsh_cnt=read(fds[2], &read_zsh[0], 255);
+				if(zsh_cnt>0)
+					{
+					char* write_net;
+					//reading from the socket can have more than one \n
+					//so replace all \n with \r\n.					
+					write_net=add_return(read_zsh);
+					if(write_net)
+						{
+						write(net, write_net, strlen(write_net));							
+						free(write_net);
+						}
+					}					
+				}				
+			}		
+		}
+	else
+		{
+		write(net, "\n\rShell is not launched", 25);
+		sleep(5);
+		exit(0); //exit here	
+		}		
+
+#endif    
+    cleanup(0);
+}
+
+#ifndef	TCSIG
+# ifdef	TIOCSIG
+#  define TCSIG TIOCSIG
+# endif
+#endif
+
+#ifdef	STREAMSPTY
+
+    int flowison = -1;  /* current state of flow: -1 is unknown */
+
+int
+readstream(int p, char *ibuf, int bufsize)
+{
+    int flags = 0;
+    int ret = 0;
+    struct termios *tsp;
+#if 0
+    struct termio *tp;
+#endif
+    struct iocblk *ip;
+    char vstop, vstart;
+    int ixon;
+    int newflow;
+
+    strbufc.maxlen = BUFSIZ;
+    strbufc.buf = (char *)ctlbuf;
+    strbufd.maxlen = bufsize-1;
+    strbufd.len = 0;
+    strbufd.buf = ibuf+1;
+    ibuf[0] = 0;
+
+    ret = getmsg(p, &strbufc, &strbufd, &flags);
+    if (ret < 0)  /* error of some sort -- probably EAGAIN */
+	return(-1);
+
+    if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) {
+	/* data message */
+	if (strbufd.len > 0) {			/* real data */
+	    return(strbufd.len + 1);	/* count header char */
+	} else {
+	    /* nothing there */
+	    errno = EAGAIN;
+	    return(-1);
+	}
+    }
+
+    /*
+     * It's a control message.  Return 1, to look at the flag we set
+     */
+
+    switch (ctlbuf[0]) {
+    case M_FLUSH:
+	if (ibuf[1] & FLUSHW)
+	    ibuf[0] = TIOCPKT_FLUSHWRITE;
+	return(1);
+
+    case M_IOCTL:
+	ip = (struct iocblk *) (ibuf+1);
+
+	switch (ip->ioc_cmd) {
+#ifdef TCSETS
+	case TCSETS:
+	case TCSETSW:
+	case TCSETSF:
+	    tsp = (struct termios *)
+		(ibuf+1 + sizeof(struct iocblk));
+	    vstop = tsp->c_cc[VSTOP];
+	    vstart = tsp->c_cc[VSTART];
+	    ixon = tsp->c_iflag & IXON;
+	    break;
+#endif
+#if 0
+	case TCSETA:
+	case TCSETAW:
+	case TCSETAF:
+	    tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk));
+	    vstop = tp->c_cc[VSTOP];
+	    vstart = tp->c_cc[VSTART];
+	    ixon = tp->c_iflag & IXON;
+	    break;
+#endif
+	default:
+	    errno = EAGAIN;
+	    return(-1);
+	}
+
+	newflow =  (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0;
+	if (newflow != flowison) {  /* it's a change */
+	    flowison = newflow;
+	    ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP;
+	    return(1);
+	}
+    }
+
+    /* nothing worth doing anything about */
+    errno = EAGAIN;
+    return(-1);
+}
+#endif /* STREAMSPTY */
+
+/*
+ * Send interrupt to process on other side of pty.
+ * If it is in raw mode, just write NULL;
+ * otherwise, write intr char.
+ */
+void
+interrupt()
+{
+    ptyflush();	/* half-hearted */
+
+#if defined(STREAMSPTY) && defined(TIOCSIGNAL)
+    /* Streams PTY style ioctl to post a signal */
+    if (really_stream)
+	{
+	    int sig = SIGINT;
+	    ioctl(ourpty, TIOCSIGNAL, &sig);
+	    ioctl(ourpty, I_FLUSH, FLUSHR);
+	}
+#else
+#ifdef	TCSIG
+    ioctl(ourpty, TCSIG, (char *)SIGINT);
+#else	/* TCSIG */
+    init_termbuf();
+    *pfrontp++ = slctab[SLC_IP].sptr ?
+	(unsigned char)*slctab[SLC_IP].sptr : '\177';
+#endif	/* TCSIG */
+#endif
+}
+
+/*
+ * Send quit to process on other side of pty.
+ * If it is in raw mode, just write NULL;
+ * otherwise, write quit char.
+ */
+void
+sendbrk()
+{
+    ptyflush();	/* half-hearted */
+#ifdef	TCSIG
+    ioctl(ourpty, TCSIG, (char *)SIGQUIT);
+#else	/* TCSIG */
+    init_termbuf();
+    *pfrontp++ = slctab[SLC_ABORT].sptr ?
+	(unsigned char)*slctab[SLC_ABORT].sptr : '\034';
+#endif	/* TCSIG */
+}
+
+void
+sendsusp()
+{
+#ifdef	SIGTSTP
+    ptyflush();	/* half-hearted */
+# ifdef	TCSIG
+    ioctl(ourpty, TCSIG, (char *)SIGTSTP);
+# else	/* TCSIG */
+    *pfrontp++ = slctab[SLC_SUSP].sptr ?
+	(unsigned char)*slctab[SLC_SUSP].sptr : '\032';
+# endif	/* TCSIG */
+#endif	/* SIGTSTP */
+}
+
+/*
+ * When we get an AYT, if ^T is enabled, use that.  Otherwise,
+ * just send back "[Yes]".
+ */
+void
+recv_ayt()
+{
+#if	defined(SIGINFO) && defined(TCSIG)
+    if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) {
+	ioctl(ourpty, TCSIG, (char *)SIGINFO);
+	return;
+    }
+#endif
+    output_data("\r\n[Yes]\r\n");
+}
+
+void
+doeof()
+{
+    init_termbuf();
+
+    *pfrontp++ = slctab[SLC_EOF].sptr ?
+	(unsigned char)*slctab[SLC_EOF].sptr : '\004';
+}