openenvutils/telnetserver/src/telnetd.c
changeset 0 2e3d3ce01487
child 1 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // telnetd.c
       
     2 //
       
     3 // © Portions Copyright (c) Symbian Software Ltd 2007-2008. All rights reserved.
       
     4 //
       
     5 /*
       
     6  * Copyright (c) 1989, 1993
       
     7  *	The Regents of the University of California.  All rights reserved.
       
     8  *
       
     9  * Redistribution and use in source and binary forms, with or without
       
    10  * modification, are permitted provided that the following conditions
       
    11  * are met:
       
    12  * 1. Redistributions of source code must retain the above copyright
       
    13  *    notice, this list of conditions and the following disclaimer.
       
    14  * 2. Redistributions in binary form must reproduce the above copyright
       
    15  *    notice, this list of conditions and the following disclaimer in the
       
    16  *    documentation and/or other materials provided with the distribution.
       
    17  * 3. Neither the name of the University nor the names of its contributors
       
    18  *    may be used to endorse or promote products derived from this software
       
    19  *    without specific prior written permission.
       
    20  *
       
    21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
       
    22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
       
    24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
       
    25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
       
    26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
       
    27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
       
    28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
       
    29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
       
    30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
       
    31  * SUCH DAMAGE.
       
    32  */
       
    33 #include "telnetd.h"
       
    34 
       
    35 #ifdef __SYMBIAN32__
       
    36 #include "dummy.h"
       
    37 extern void mini_inetd (int port);
       
    38 #endif
       
    39 
       
    40 #ifndef __SYMBIAN32__
       
    41 __RCSID("$Heimdal: telnetd.c,v 1.69.6.1 2004/03/22 18:17:25 lha Exp $"
       
    42         "$NetBSD: telnetd.c,v 1.3 2004/04/02 14:59:47 lha Exp $");
       
    43 #endif
       
    44 
       
    45 #ifdef _SC_CRAY_SECURE_SYS
       
    46 #include <sys/sysv.h>
       
    47 #include <sys/secdev.h>
       
    48 #include <sys/secparm.h>
       
    49 #include <sys/usrv.h>
       
    50 int	secflag;
       
    51 char	tty_dev[16];
       
    52 struct	secdev dv;
       
    53 struct	sysv sysv;
       
    54 struct	socksec ss;
       
    55 #endif	/* _SC_CRAY_SECURE_SYS */
       
    56 
       
    57 #ifdef AUTHENTICATION
       
    58 int	auth_level = 0;
       
    59 #endif
       
    60 
       
    61 
       
    62 #ifdef __SYMBIAN32__
       
    63 #ifdef __WINSCW__
       
    64 #pragma warn_unusedarg off
       
    65 #endif
       
    66 #endif
       
    67 
       
    68 extern	int utmp_len;
       
    69 int	registerd_host_only = 0;
       
    70 
       
    71 /**moved from roken.h**/
       
    72 #define roken_getservbyname(x,y) getservbyname(x,y)
       
    73 #define roken_openlog(a,b,c) openlog(a,b,c)
       
    74 #define roken_getsockname(a,b,c) getsockname(a,b,c)
       
    75 
       
    76 #undef NOERROR
       
    77 
       
    78 #ifdef	STREAMSPTY
       
    79 # include <stropts.h>
       
    80 # include <termios.h>
       
    81 #ifdef HAVE_SYS_UIO_H
       
    82 #include <sys/uio.h>
       
    83 #endif /* HAVE_SYS_UIO_H */
       
    84 #ifdef HAVE_SYS_STREAM_H
       
    85 #include <sys/stream.h>
       
    86 #endif
       
    87 
       
    88 #ifdef _AIX
       
    89 #include <sys/termio.h>
       
    90 #endif
       
    91 # ifdef HAVE_SYS_STRTTY_H
       
    92 # include <sys/strtty.h>
       
    93 # endif
       
    94 # ifdef HAVE_SYS_STR_TTY_H
       
    95 # include <sys/str_tty.h>
       
    96 # endif
       
    97 /* make sure we don't get the bsd version */
       
    98 /* what is this here for? solaris? /joda */
       
    99 # ifdef HAVE_SYS_TTY_H
       
   100 # include "/usr/include/sys/tty.h"
       
   101 # endif
       
   102 # ifdef HAVE_SYS_PTYVAR_H
       
   103 # include <sys/ptyvar.h>
       
   104 # endif
       
   105 
       
   106 /*
       
   107  * Because of the way ptyibuf is used with streams messages, we need
       
   108  * ptyibuf+1 to be on a full-word boundary.  The following wierdness
       
   109  * is simply to make that happen.
       
   110  */
       
   111 
       
   112 long	ptyibufbuf[BUFSIZ/sizeof(long)+1];
       
   113 char	*ptyibuf = ((char *)&ptyibufbuf[1])-1;
       
   114 char	*ptyip = ((char *)&ptyibufbuf[1])-1;
       
   115 char	ptyibuf2[BUFSIZ];
       
   116 unsigned char ctlbuf[BUFSIZ];
       
   117 struct	strbuf strbufc, strbufd;
       
   118 
       
   119 int readstream(int, char*, int);
       
   120 
       
   121 #else	/* ! STREAMPTY */
       
   122 
       
   123 /*
       
   124  * I/O data buffers,
       
   125  * pointers, and counters.
       
   126  */
       
   127 char	ptyibuf[BUFSIZ], *ptyip = ptyibuf;
       
   128 char	ptyibuf2[BUFSIZ];
       
   129 
       
   130 #endif /* ! STREAMPTY */
       
   131 
       
   132 int	hostinfo = 1;			/* do we print login banner? */
       
   133 
       
   134 #ifdef	_CRAY
       
   135 extern int      newmap; /* nonzero if \n maps to ^M^J */
       
   136 int	lowpty = 0, highpty;	/* low, high pty numbers */
       
   137 #endif /* CRAY */
       
   138 
       
   139 int debug = 1;
       
   140 int keepalive = 1;
       
   141 char *progname;
       
   142 
       
   143 static void usage (void);
       
   144 
       
   145 /*
       
   146  * The string to pass to getopt().  We do it this way so
       
   147  * that only the actual options that we support will be
       
   148  * passed off to getopt().
       
   149  */
       
   150 char valid_opts[] = "Bd:hklnS:u:UL:y"
       
   151 #ifdef AUTHENTICATION
       
   152 		    "a:X:z"
       
   153 #endif
       
   154 #ifdef DIAGNOSTICS
       
   155 		    "D:"
       
   156 #endif
       
   157 #ifdef _CRAY
       
   158 		    "r:"
       
   159 #endif
       
   160 		    ;
       
   161 
       
   162 static void doit(struct sockaddr*, int);
       
   163 
       
   164 #ifdef ENCRYPTION
       
   165 extern int des_check_key;
       
   166 #endif
       
   167 
       
   168 extern int getConnectionUp(void);
       
   169 
       
   170 int
       
   171 main(int argc, char **argv)
       
   172 {
       
   173     struct sockaddr_storage __ss;
       
   174     struct sockaddr *sa = (struct sockaddr *)&__ss;
       
   175     int on = 1;
       
   176     socklen_t sa_size;
       
   177     int ch;
       
   178 #if	defined(IPPROTO_IP) && defined(IP_TOS)
       
   179     int tos = -1;
       
   180 #endif
       
   181 #ifdef ENCRYPTION
       
   182     des_check_key = 1;	/* Kludge for Mac NCSA telnet 2.6 /bg */
       
   183 #endif
       
   184 
       
   185 	pfrontp = pbackp = ptyobuf;
       
   186     netip = netibuf;
       
   187     nfrontp = nbackp = netobuf;
       
   188 	    
       
   189 #ifdef __SYMBIAN32__
       
   190 	if( getConnectionUp() < 0) exit(1);
       
   191 #endif	
       
   192 
       
   193     setprogname(argv[0]);
       
   194 
       
   195     progname = *argv;
       
   196 #ifdef ENCRYPTION
       
   197     nclearto = 0;
       
   198 #endif
       
   199 
       
   200 #ifdef _CRAY
       
   201     /*
       
   202      * Get number of pty's before trying to process options,
       
   203      * which may include changing pty range.
       
   204      */
       
   205     highpty = getnpty();
       
   206 #endif /* CRAY */
       
   207 
       
   208     if (argc == 2 && strcmp(argv[1], "--version") == 0) {
       
   209 #ifndef __SYMBIAN32__
       
   210 	print_version(NULL); 
       
   211 #endif //__SYMBIAN32__
       
   212 	exit(0);
       
   213     }
       
   214 
       
   215     while ((ch = getopt(argc, argv, valid_opts)) != -1) {
       
   216 	switch(ch) {
       
   217 
       
   218 #ifdef	AUTHENTICATION
       
   219 	case 'a':
       
   220 	    /*
       
   221 	     * Check for required authentication level
       
   222 	     */
       
   223 	    if (strcmp(optarg, "debug") == 0) {
       
   224 		auth_debug_mode = 1;
       
   225 	    } else if (strcasecmp(optarg, "none") == 0) {
       
   226 		auth_level = 0;
       
   227 	    } else if (strcasecmp(optarg, "otp") == 0) {
       
   228 		auth_level = 0;
       
   229 		require_otp = 1;
       
   230 	    } else if (strcasecmp(optarg, "other") == 0) {
       
   231 		auth_level = AUTH_OTHER;
       
   232 	    } else if (strcasecmp(optarg, "user") == 0) {
       
   233 		auth_level = AUTH_USER;
       
   234 	    } else if (strcasecmp(optarg, "valid") == 0) {
       
   235 		auth_level = AUTH_VALID;
       
   236 	    } else if (strcasecmp(optarg, "off") == 0) {
       
   237 		/*
       
   238 		 * This hack turns off authentication
       
   239 		 */
       
   240 		auth_level = -1;
       
   241 	    } else {
       
   242 		fprintf(stderr,
       
   243 			"telnetd: unknown authorization level for -a\n");
       
   244 	    }
       
   245 	    break;
       
   246 #endif	/* AUTHENTICATION */
       
   247 
       
   248 	case 'B': /* BFTP mode is not supported any more */
       
   249 	    break;
       
   250 	case 'd':
       
   251 	    if (strcmp(optarg, "ebug") == 0) {
       
   252 		debug++;
       
   253 		break;
       
   254 	    }
       
   255 	    usage();
       
   256 	    /* NOTREACHED */
       
   257 	    break;
       
   258 
       
   259 #ifdef DIAGNOSTICS
       
   260 	case 'D':
       
   261 	    /*
       
   262 	     * Check for desired diagnostics capabilities.
       
   263 	     */
       
   264 	    if (!strcmp(optarg, "report")) {
       
   265 		diagnostic |= TD_REPORT|TD_OPTIONS;
       
   266 	    } else if (!strcmp(optarg, "exercise")) {
       
   267 		diagnostic |= TD_EXERCISE;
       
   268 	    } else if (!strcmp(optarg, "netdata")) {
       
   269 		diagnostic |= TD_NETDATA;
       
   270 	    } else if (!strcmp(optarg, "ptydata")) {
       
   271 		diagnostic |= TD_PTYDATA;
       
   272 	    } else if (!strcmp(optarg, "options")) {
       
   273 		diagnostic |= TD_OPTIONS;
       
   274 	    } else {
       
   275 		usage();
       
   276 		/* NOT REACHED */
       
   277 	    }
       
   278 	    break;
       
   279 #endif /* DIAGNOSTICS */
       
   280 
       
   281 
       
   282 	case 'h':
       
   283 	    hostinfo = 0;
       
   284 	    break;
       
   285 
       
   286 	case 'k': /* Linemode is not supported any more */
       
   287 	case 'l':
       
   288 	    break;
       
   289 
       
   290 	case 'n':
       
   291 	    keepalive = 0;
       
   292 	    break;
       
   293 
       
   294 #ifdef _CRAY
       
   295 	case 'r':
       
   296 	    {
       
   297 		char *strchr();
       
   298 		char *c;
       
   299 
       
   300 		/*
       
   301 		 * Allow the specification of alterations
       
   302 		 * to the pty search range.  It is legal to
       
   303 		 * specify only one, and not change the
       
   304 		 * other from its default.
       
   305 		 */
       
   306 		c = strchr(optarg, '-');
       
   307 		if (c) {
       
   308 		    *c++ = '\0';
       
   309 		    highpty = atoi(c);
       
   310 		}
       
   311 		if (*optarg != '\0')
       
   312 		    lowpty = atoi(optarg);
       
   313 		if ((lowpty > highpty) || (lowpty < 0) ||
       
   314 		    (highpty > 32767)) {
       
   315 		    usage();
       
   316 		    /* NOT REACHED */
       
   317 		}
       
   318 		break;
       
   319 	    }
       
   320 #endif	/* CRAY */
       
   321 
       
   322 	case 'S':
       
   323 #ifdef	HAVE_PARSETOS
       
   324 	    if ((tos = parsetos(optarg, "tcp")) < 0)
       
   325 		fprintf(stderr, "%s%s%s\n",
       
   326 			"telnetd: Bad TOS argument '", optarg,
       
   327 			"'; will try to use default TOS");
       
   328 #else
       
   329 	    fprintf(stderr, "%s%s\n", "TOS option unavailable; ",
       
   330 		    "-S flag not supported\n");
       
   331 #endif
       
   332 	    break;
       
   333 
       
   334 	case 'u': {
       
   335 	    char *eptr;
       
   336 
       
   337 	    utmp_len = strtol(optarg, &eptr, 0);
       
   338 	    if (optarg == eptr)
       
   339 		fprintf(stderr, "telnetd: unknown utmp len (%s)\n", optarg);
       
   340 	    break;
       
   341 	}
       
   342 
       
   343 	case 'U':
       
   344 	    registerd_host_only = 1;
       
   345 	    break;
       
   346 
       
   347 #ifdef	AUTHENTICATION
       
   348 	case 'X':
       
   349 	    /*
       
   350 	     * Check for invalid authentication types
       
   351 	     */
       
   352 	    auth_disable_name(optarg);
       
   353 	    break;
       
   354 #endif
       
   355 	case 'y':
       
   356 	    no_warn = 1;
       
   357 	    break;
       
   358 #ifdef AUTHENTICATION
       
   359 	case 'z':
       
   360 	    log_unauth = 1;
       
   361 	    break;
       
   362 
       
   363 #endif	/* AUTHENTICATION */
       
   364 
       
   365 	case 'L':
       
   366 	    new_login = optarg;
       
   367 	    break;
       
   368 			
       
   369 	default:
       
   370 	    fprintf(stderr, "telnetd: %c: unknown option\n", ch);
       
   371 	    /* FALLTHROUGH */
       
   372 	case '?':
       
   373 	    usage();
       
   374 	    /* NOTREACHED */
       
   375 	}
       
   376     }
       
   377 
       
   378     argc -= optind;
       
   379     argv += optind;
       
   380 
       
   381     if (debug) {
       
   382 	int port = 0;
       
   383 	struct servent *sp;
       
   384 
       
   385 	if (argc > 1) {
       
   386 	    usage ();
       
   387 	} else if (argc == 1) {
       
   388 	    sp = (struct servent*)roken_getservbyname (*argv, "tcp");
       
   389 	    if (sp)
       
   390 		port = sp->s_port;
       
   391 	    else
       
   392 		port = htons(atoi(*argv));
       
   393 	} else {
       
   394 #ifdef 	__SYMBIAN32__
       
   395 		port = htons(atoi("23"));		
       
   396 #else
       
   397 #ifdef KRB5
       
   398 	    port = krb5_getportbyname (NULL, "telnet", "tcp", 23);
       
   399 #else
       
   400 	    port = k_getportbyname("telnet", "tcp", htons(23));
       
   401 #endif
       
   402 #endif //__SYMBIAN32__
       
   403 	}
       
   404 	mini_inetd (port);
       
   405     } else if (argc > 0) {
       
   406 	usage();
       
   407 	/* NOT REACHED */
       
   408     }
       
   409 
       
   410 #ifdef _SC_CRAY_SECURE_SYS
       
   411     secflag = sysconf(_SC_CRAY_SECURE_SYS);
       
   412 
       
   413     /*
       
   414      *	Get socket's security label
       
   415      */
       
   416     if (secflag)  {
       
   417 	socklen_t szss = sizeof(ss);
       
   418 	int sock_multi;
       
   419 	socklen_t szi = sizeof(int);
       
   420 
       
   421 	memset(&dv, 0, sizeof(dv));
       
   422 
       
   423 	if (getsysv(&sysv, sizeof(struct sysv)) != 0) 
       
   424 	    fatalperror(net, "getsysv");
       
   425 
       
   426 	/*
       
   427 	 *	Get socket security label and set device values
       
   428 	 *	   {security label to be set on ttyp device}
       
   429 	 */
       
   430 #ifdef SO_SEC_MULTI			/* 8.0 code */
       
   431 	if ((getsockopt(0, SOL_SOCKET, SO_SECURITY,
       
   432 			(void *)&ss, &szss) < 0) ||
       
   433 	    (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI,
       
   434 			(void *)&sock_multi, &szi) < 0)) 
       
   435 	    fatalperror(net, "getsockopt");
       
   436 	else {
       
   437 	    dv.dv_actlvl = ss.ss_actlabel.lt_level;
       
   438 	    dv.dv_actcmp = ss.ss_actlabel.lt_compart;
       
   439 	    if (!sock_multi) {
       
   440 		dv.dv_minlvl = dv.dv_maxlvl = dv.dv_actlvl;
       
   441 		dv.dv_valcmp = dv.dv_actcmp;
       
   442 	    } else {
       
   443 		dv.dv_minlvl = ss.ss_minlabel.lt_level;
       
   444 		dv.dv_maxlvl = ss.ss_maxlabel.lt_level;
       
   445 		dv.dv_valcmp = ss.ss_maxlabel.lt_compart;
       
   446 	    }
       
   447 	    dv.dv_devflg = 0;
       
   448 	}
       
   449 #else /* SO_SEC_MULTI */		/* 7.0 code */
       
   450 	if (getsockopt(0, SOL_SOCKET, SO_SECURITY,
       
   451 		       (void *)&ss, &szss) >= 0) {
       
   452 	    dv.dv_actlvl = ss.ss_slevel;
       
   453 	    dv.dv_actcmp = ss.ss_compart;
       
   454 	    dv.dv_minlvl = ss.ss_minlvl;
       
   455 	    dv.dv_maxlvl = ss.ss_maxlvl;
       
   456 	    dv.dv_valcmp = ss.ss_maxcmp;
       
   457 	}
       
   458 #endif /* SO_SEC_MULTI */
       
   459     }
       
   460 #endif	/* _SC_CRAY_SECURE_SYS */
       
   461 
       
   462  
       
   463     roken_openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
       
   464     sa_size = sizeof (__ss);
       
   465     
       
   466     if (getpeername(STDIN_FILENO, sa, &sa_size) < 0) {
       
   467 	fprintf(stderr, "%s: ", progname);
       
   468 	perror("getpeername");
       
   469 	_exit(1);
       
   470     }
       
   471 
       
   472     if (keepalive &&
       
   473 	setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE,
       
   474 		   (void *)&on, sizeof (on)) < 0) {		 
       
   475 #ifndef __SYMBIAN32__		     
       
   476 	syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
       
   477 #endif
       
   478 	;
       
   479     }
       
   480     
       
   481 
       
   482 #if	defined(IPPROTO_IP) && defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
       
   483     {
       
   484 # ifdef HAVE_GETTOSBYNAME
       
   485 	struct tosent *tp;
       
   486 	if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
       
   487 	    tos = tp->t_tos;
       
   488 # endif
       
   489 	if (tos < 0)
       
   490 	    tos = 020;	/* Low Delay bit */
       
   491 	if (tos
       
   492 	    && sa->sa_family == AF_INET
       
   493 	    && (setsockopt(STDIN_FILENO, IPPROTO_IP, IP_TOS,
       
   494 			   (void *)&tos, sizeof(tos)) < 0)
       
   495 	    && (errno != ENOPROTOOPT) )
       
   496 	    syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
       
   497     }
       
   498 #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
       
   499     net = STDIN_FILENO;
       
   500     doit(sa, sa_size);
       
   501     /* NOTREACHED */
       
   502     return 0;
       
   503 }  /* end of main */
       
   504 
       
   505 static void
       
   506 usage(void)
       
   507 {
       
   508     fprintf(stderr, "Usage: telnetd");
       
   509 #ifdef	AUTHENTICATION
       
   510     fprintf(stderr, " [-a (debug|other|otp|user|valid|off|none)]\n\t");
       
   511 #endif
       
   512     fprintf(stderr, " [-debug]");
       
   513 #ifdef DIAGNOSTICS
       
   514     fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
       
   515 #endif
       
   516 #ifdef	AUTHENTICATION
       
   517     fprintf(stderr, " [-edebug]");
       
   518 #endif
       
   519     fprintf(stderr, " [-h]");
       
   520     fprintf(stderr, " [-L login]");
       
   521     fprintf(stderr, " [-n]");
       
   522 #ifdef	_CRAY
       
   523     fprintf(stderr, " [-r[lowpty]-[highpty]]");
       
   524 #endif
       
   525     fprintf(stderr, "\n\t");
       
   526 #ifdef	HAVE_GETTOSBYNAME
       
   527     fprintf(stderr, " [-S tos]");
       
   528 #endif
       
   529 #ifdef	AUTHENTICATION
       
   530     fprintf(stderr, " [-X auth-type] [-y] [-z]");
       
   531 #endif
       
   532     fprintf(stderr, " [-u utmp_hostname_length] [-U]");
       
   533     fprintf(stderr, " [port]\n");
       
   534     exit(1);
       
   535 }
       
   536 
       
   537 /*
       
   538  * getterminaltype
       
   539  *
       
   540  *	Ask the other end to send along its terminal type and speed.
       
   541  * Output is the variable terminaltype filled in.
       
   542  */
       
   543 static unsigned char ttytype_sbbuf[] = {
       
   544     IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE
       
   545 };
       
   546 
       
   547 int
       
   548 getterminaltype(char *name, size_t name_sz)
       
   549 {
       
   550     int retval = -1;
       
   551 
       
   552     settimer(baseline);
       
   553 #ifdef AUTHENTICATION
       
   554     /*
       
   555      * Handle the Authentication option before we do anything else.
       
   556      */
       
   557     send_do(TELOPT_AUTHENTICATION, 1);
       
   558     while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
       
   559 	ttloop();
       
   560     if (his_state_is_will(TELOPT_AUTHENTICATION)) {
       
   561 	retval = auth_wait(name, name_sz);
       
   562     }
       
   563 #endif
       
   564 
       
   565 #ifdef ENCRYPTION
       
   566     send_will(TELOPT_ENCRYPT, 1);
       
   567     send_do(TELOPT_ENCRYPT, 1);	/* esc@magic.fi */
       
   568 #endif
       
   569     send_do(TELOPT_TTYPE, 1);
       
   570     send_do(TELOPT_TSPEED, 1);
       
   571     send_do(TELOPT_XDISPLOC, 1);
       
   572     send_do(TELOPT_NEW_ENVIRON, 1);
       
   573     send_do(TELOPT_OLD_ENVIRON, 1);
       
   574     while (
       
   575 #ifdef ENCRYPTION
       
   576 	   his_do_dont_is_changing(TELOPT_ENCRYPT) ||
       
   577 #endif
       
   578 	   his_will_wont_is_changing(TELOPT_TTYPE) ||
       
   579 	   his_will_wont_is_changing(TELOPT_TSPEED) ||
       
   580 	   his_will_wont_is_changing(TELOPT_XDISPLOC) ||
       
   581 	   his_will_wont_is_changing(TELOPT_NEW_ENVIRON) ||
       
   582 	   his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) {
       
   583 	ttloop();
       
   584     }
       
   585 #ifdef ENCRYPTION
       
   586     /*
       
   587      * Wait for the negotiation of what type of encryption we can
       
   588      * send with.  If autoencrypt is not set, this will just return.
       
   589      */
       
   590     if (his_state_is_will(TELOPT_ENCRYPT)) {
       
   591 	encrypt_wait();
       
   592     }
       
   593 #endif
       
   594     if (his_state_is_will(TELOPT_TSPEED)) {
       
   595 	static unsigned char sb[] =
       
   596 	{ IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
       
   597 
       
   598 	telnet_net_write (sb, sizeof sb);
       
   599 	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
       
   600     }
       
   601     if (his_state_is_will(TELOPT_XDISPLOC)) {
       
   602 	static unsigned char sb[] =
       
   603 	{ IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
       
   604 
       
   605 	telnet_net_write (sb, sizeof sb);
       
   606 	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
       
   607     }
       
   608     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
       
   609 	static unsigned char sb[] =
       
   610 	{ IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE };
       
   611 
       
   612 	telnet_net_write (sb, sizeof sb);
       
   613 	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
       
   614     }
       
   615     else if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
       
   616 	static unsigned char sb[] =
       
   617 	{ IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE };
       
   618 
       
   619 	telnet_net_write (sb, sizeof sb);
       
   620 	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
       
   621     }
       
   622     if (his_state_is_will(TELOPT_TTYPE)) {
       
   623 
       
   624 	telnet_net_write (ttytype_sbbuf, sizeof ttytype_sbbuf);
       
   625 	DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
       
   626 				  sizeof ttytype_sbbuf - 2););
       
   627     }
       
   628     if (his_state_is_will(TELOPT_TSPEED)) {
       
   629 	while (sequenceIs(tspeedsubopt, baseline))
       
   630 	    ttloop();
       
   631     }
       
   632     if (his_state_is_will(TELOPT_XDISPLOC)) {
       
   633 	while (sequenceIs(xdisplocsubopt, baseline))
       
   634 	    ttloop();
       
   635     }
       
   636     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
       
   637 	while (sequenceIs(environsubopt, baseline))
       
   638 	    ttloop();
       
   639     }
       
   640     if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
       
   641 	while (sequenceIs(oenvironsubopt, baseline))
       
   642 	    ttloop();
       
   643     }
       
   644     if (his_state_is_will(TELOPT_TTYPE)) {
       
   645 	char first[256], last[256];
       
   646 
       
   647 	while (sequenceIs(ttypesubopt, baseline))
       
   648 	    ttloop();
       
   649 
       
   650 	/*
       
   651 	 * If the other side has already disabled the option, then
       
   652 	 * we have to just go with what we (might) have already gotten.
       
   653 	 */
       
   654 	if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
       
   655 	    strlcpy(first, terminaltype, sizeof(first));
       
   656 	    for(;;) {
       
   657 		/*
       
   658 		 * Save the unknown name, and request the next name.
       
   659 		 */
       
   660 		strlcpy(last, terminaltype, sizeof(last));
       
   661 		_gettermname();
       
   662 		if (terminaltypeok(terminaltype))
       
   663 		    break;
       
   664 		if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
       
   665 		    his_state_is_wont(TELOPT_TTYPE)) {
       
   666 		    /*
       
   667 		     * We've hit the end.  If this is the same as
       
   668 		     * the first name, just go with it.
       
   669 		     */
       
   670 		    if (strncmp(first, terminaltype, sizeof(first)) == 0)
       
   671 			break;
       
   672 		    /*
       
   673 		     * Get the terminal name one more time, so that
       
   674 		     * RFC1091 compliant telnets will cycle back to
       
   675 		     * the start of the list.
       
   676 		     */
       
   677 		    _gettermname();
       
   678 		    if (strncmp(first, terminaltype, sizeof(first)) != 0)
       
   679 			strcpy(terminaltype, first);
       
   680 		    break;
       
   681 		}
       
   682 	    }
       
   683 	}
       
   684     }
       
   685     return(retval);
       
   686 }  /* end of getterminaltype */
       
   687 
       
   688 void
       
   689 _gettermname(void)
       
   690 {
       
   691     /*
       
   692      * If the client turned off the option,
       
   693      * we can't send another request, so we
       
   694      * just return.
       
   695      */
       
   696     if (his_state_is_wont(TELOPT_TTYPE))
       
   697 	return;
       
   698     settimer(baseline);
       
   699     telnet_net_write (ttytype_sbbuf, sizeof ttytype_sbbuf);
       
   700     DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
       
   701 			      sizeof ttytype_sbbuf - 2););
       
   702     while (sequenceIs(ttypesubopt, baseline))
       
   703 	ttloop();
       
   704 }
       
   705 
       
   706 int
       
   707 terminaltypeok(char *s)
       
   708 {
       
   709     return 1;
       
   710 }
       
   711 
       
   712 
       
   713 char host_name[MAXHOSTNAMELEN];
       
   714 char remote_host_name[MAXHOSTNAMELEN];
       
   715 char remote_utmp_name[MAXHOSTNAMELEN];
       
   716 
       
   717 static int
       
   718 getnameinfo_verified(const struct sockaddr *sa, socklen_t salen,
       
   719 		     char *host, size_t hostlen,
       
   720 		     char *serv, size_t servlen,
       
   721 		     int flags)
       
   722 {
       
   723     int ret;
       
   724     struct addrinfo *ai, *a;
       
   725     char servbuf[NI_MAXSERV];
       
   726     struct addrinfo hints;
       
   727 
       
   728     if (host == NULL)
       
   729 	return EAI_NONAME;
       
   730 
       
   731     if (serv == NULL) {
       
   732 	serv = servbuf;
       
   733 	servlen = sizeof(servbuf);
       
   734     }
       
   735 
       
   736     ret = getnameinfo (sa, salen, host, hostlen, serv, servlen,
       
   737 		       flags | NI_NUMERICSERV);
       
   738     if (ret)
       
   739 	goto fail;
       
   740 
       
   741     memset (&hints, 0, sizeof(hints));
       
   742     hints.ai_socktype = SOCK_STREAM;
       
   743     ret = getaddrinfo (host, serv, &hints, &ai);
       
   744     if (ret)
       
   745 	goto fail;
       
   746     for (a = ai; a != NULL; a = a->ai_next) {
       
   747 	if (a->ai_addrlen == salen
       
   748 	    && memcmp (a->ai_addr, sa, salen) == 0) {
       
   749 	    freeaddrinfo (ai);
       
   750 	    return 0;
       
   751 	}
       
   752     }
       
   753     freeaddrinfo (ai);
       
   754  fail:
       
   755     if (flags & NI_NAMEREQD)
       
   756 	return EAI_NONAME;
       
   757     ret = getnameinfo (sa, salen, host, hostlen, serv, servlen,
       
   758 		       flags | NI_NUMERICSERV | NI_NUMERICHOST);
       
   759     return ret;
       
   760 }
       
   761 
       
   762 #ifdef __SYMBIAN32__
       
   763 //replace the ocurrences of \n with \n\r.
       
   764 //caller should free the memory
       
   765 char* add_return(char* source)
       
   766 	{
       
   767 	int occur=0, len=0, tokens=0, occurbk=0;
       
   768 	char *token, *ret; 
       
   769 	
       
   770 	if(NULL==source || !(len=strlen(source)))
       
   771 		return NULL;
       
   772 
       
   773 	ret=(char*)calloc(len+1, sizeof(char));	
       
   774 	strcpy(ret, source);
       
   775 	
       
   776 	
       
   777 	occur=source[len-1]=='\n'? 1:0;
       
   778 	if(len>1 && source[0]=='\n')
       
   779 		occur+=1;
       
   780 		
       
   781 	//find the no. of occurrences of \n
       
   782 	token=strtok(source, "\n");
       
   783 	while(token)
       
   784 		{	
       
   785 		token=strtok(NULL, "\n");				
       
   786 		tokens++;
       
   787 		}
       
   788 
       
   789 	occurbk=occur=tokens>1?tokens+occur-1: occur;
       
   790 	if(occur<=0)
       
   791 		{
       
   792 		return ret;
       
   793 		}		
       
   794 	
       
   795 	//start replacing with \n\r	
       
   796 	
       
   797 	/* start moving from end of the string. 
       
   798 	 * If the no. of occurences of \n is n(n set), then move the nth set
       
   799 	 * to n bytes forward and n-1th set to n-1 bytes forward and similarly 
       
   800 	 * for the rest until it reaches the first set.
       
   801  	 */	
       
   802 	ret=(char*)realloc(ret, (sizeof(char)*(len+occur+1)));
       
   803 	if(ret)
       
   804 		{
       
   805 		
       
   806 		int counter=len-1;
       
   807 		while(occur>0 && counter>0)
       
   808 			{
       
   809 			while(ret[counter]!='\n')
       
   810 				{
       
   811 				ret[counter+occur]=ret[counter];
       
   812 				counter--;								
       
   813 				}
       
   814 			ret[counter+occur-1]='\n';					
       
   815 			ret[counter+occur]='\r';	
       
   816 			counter--;
       
   817 			occur--;				
       
   818 			}
       
   819 		ret[len+occurbk]='\0'; //terminate the entire string	
       
   820 		}		
       
   821 	return ret;		
       
   822 	}
       
   823 	
       
   824 	
       
   825 void readinput(char* line_o, int* length, int size)								
       
   826 {
       
   827 	char read_c;
       
   828 	if(!line_o || !length)
       
   829 		return;
       
   830 		
       
   831 	*length=0;
       
   832 	read(net, &read_c, 1);																			
       
   833 	while(read_c!='\n')	//read the command from client		
       
   834 		{						
       
   835 		if(*length==size-1)
       
   836 			break;						
       
   837 		
       
   838 		if(read_c=='\r')
       
   839 			{
       
   840 			read(net, &read_c, 1);
       
   841 			line_o[(*length)++]='\n';
       
   842 			break;
       
   843 			}
       
   844 		write(net, &read_c, 1);	
       
   845 		line_o[(*length)++]=read_c;
       
   846 		read(net, &read_c, 1);
       
   847 		}
       
   848 		
       
   849 	line_o[*length]='\0';
       
   850 }
       
   851 #endif
       
   852 
       
   853 /*
       
   854  * Get a pty, scan input lines.
       
   855  */
       
   856 static void
       
   857 doit(struct sockaddr *who, int who_len)
       
   858 {
       
   859 #ifndef __SYMBIAN32__     
       
   860     int level;
       
   861     int ptynum;
       
   862     int error;
       
   863     char user_name[256];        
       
   864     /*
       
   865      * Find an available pty to use.
       
   866      */
       
   867     ourpty = getpty(&ptynum);
       
   868     if (ourpty < 0)
       
   869 	fatal(net, "All network ports in use");
       
   870 
       
   871 #ifdef _SC_CRAY_SECURE_SYS
       
   872     /*
       
   873      *	set ttyp line security label
       
   874      */
       
   875     if (secflag) {
       
   876 	char slave_dev[16];
       
   877 
       
   878 	snprintf(tty_dev, sizeof(tty_dev), "/dev/pty/%03d", ptynum);
       
   879 	if (setdevs(tty_dev, &dv) < 0)
       
   880 	    fatal(net, "cannot set pty security");
       
   881 	snprintf(slave_dev, sizeof(slave_dev), "/dev/ttyp%03d", ptynum);
       
   882 	if (setdevs(slave_dev, &dv) < 0)
       
   883 	    fatal(net, "cannot set tty security");
       
   884     }
       
   885 #endif	/* _SC_CRAY_SECURE_SYS */
       
   886     error = getnameinfo_verified (who, who_len,
       
   887 				  remote_host_name,
       
   888 				  sizeof(remote_host_name),
       
   889 				  NULL, 0, 
       
   890 				  registerd_host_only ? NI_NAMEREQD : 0);
       
   891     if (error)
       
   892 	fatal(net, "Couldn't resolve your address into a host name.\r\n\
       
   893 Please contact your net administrator");
       
   894 
       
   895     gethostname(host_name, sizeof (host_name));
       
   896 
       
   897     strlcpy (remote_utmp_name, remote_host_name, sizeof(remote_utmp_name));
       
   898 
       
   899     /* Only trim if too long (and possible) */
       
   900     if (strlen(remote_utmp_name) > utmp_len) {
       
   901 	char *domain = strchr(host_name, '.');
       
   902 	char *p = strchr(remote_utmp_name, '.');
       
   903 	if (domain != NULL && p != NULL && (strcmp(p, domain) == 0))
       
   904 	    *p = '\0'; /* remove domain part */
       
   905     }
       
   906 
       
   907     /*
       
   908      * If hostname still doesn't fit utmp, use ipaddr.
       
   909      */
       
   910     if (strlen(remote_utmp_name) > utmp_len) {
       
   911 	error = getnameinfo (who, who_len,
       
   912 			     remote_utmp_name,
       
   913 			     sizeof(remote_utmp_name),
       
   914 			     NULL, 0,
       
   915 			     NI_NUMERICHOST);
       
   916 	if (error)
       
   917 	    fatal(net, "Couldn't get numeric address\r\n");
       
   918     }
       
   919 
       
   920 #ifdef AUTHENTICATION
       
   921     auth_encrypt_init(host_name, remote_host_name, "TELNETD", 1);
       
   922 #endif
       
   923 
       
   924     init_env();
       
   925     /*
       
   926      * get terminal type.
       
   927      */
       
   928     *user_name = 0;
       
   929     level = getterminaltype(user_name, sizeof(user_name));
       
   930     setenv("TERM", terminaltype ? terminaltype : "network", 1);
       
   931 
       
   932 #ifdef _SC_CRAY_SECURE_SYS
       
   933     if (secflag) {
       
   934 	if (setulvl(dv.dv_actlvl) < 0)
       
   935 	    fatal(net,"cannot setulvl()");
       
   936 	if (setucmp(dv.dv_actcmp) < 0)
       
   937 	    fatal(net, "cannot setucmp()");
       
   938     }
       
   939 #endif	/* _SC_CRAY_SECURE_SYS */
       
   940 #endif //__SYMBIAN32__
       
   941     /* begin server processing */
       
   942     my_telnet();	      
       
   943 	      
       
   944     /*NOTREACHED*/
       
   945 }  /* end of doit */
       
   946 
       
   947 #ifdef __SYMBIAN32__
       
   948 
       
   949 #define PASSKEY_MAXLEN 8
       
   950 
       
   951 static
       
   952 int clientAuthentication(char* dev_key)
       
   953 {
       
   954 
       
   955 	char* get_key="Enter Key: ";
       
   956 	fd_set read_fds;    		    	
       
   957     struct timeval tv;
       
   958   	char client_buf[PASSKEY_MAXLEN+1];  
       
   959   	char read_c;
       
   960 	int buf_len=0;
       
   961 		
       
   962     if(dev_key==NULL)
       
   963     	return 1;
       
   964     
       
   965 	write(net, get_key, strlen(get_key));
       
   966     FD_ZERO(&read_fds);
       
   967 	FD_SET(net, &read_fds); 	
       
   968 
       
   969 	tv.tv_sec = 60;
       
   970 	tv.tv_usec = 0;  
       
   971 
       
   972 	//exit if nothing is read for 60 secs
       
   973 	if(select(net+1, &read_fds, NULL, NULL, &tv)==0)
       
   974 		{
       
   975 		char* login_timout="Authentication Failure:\
       
   976 			 	timeout\n";
       
   977 			 	
       
   978 		write(1, login_timout, strlen(login_timout));
       
   979 		exit(1);
       
   980 		}
       
   981 	
       
   982 	if(FD_ISSET(net, &read_fds))
       
   983 		{
       
   984 		while(buf_len < PASSKEY_MAXLEN)
       
   985 			{
       
   986 			read(net, &read_c, 1); //read from socket fd
       
   987 			switch(read_c)
       
   988 				{
       
   989 				case '\n':
       
   990 					goto jump_out; 
       
   991 				
       
   992 				case '\b':
       
   993 					//ignore previous character.
       
   994 					write(net, "\b", 1);
       
   995 					if(buf_len > 0)
       
   996 						buf_len--;
       
   997 					
       
   998 				case '\r':
       
   999 					break;
       
  1000 					
       
  1001 				default:
       
  1002 					//let all other keys be part of the passkey.
       
  1003 					write(net, "*", 1);
       
  1004 					client_buf[buf_len++]=read_c;										
       
  1005 					break;
       
  1006 				}
       
  1007 			}
       
  1008 		
       
  1009 jump_out:
       
  1010 		//pass key max length has reached or '\r\n' is entered.
       
  1011 		write(net, "\r\n", 2); 
       
  1012 		client_buf[buf_len]='\0';
       
  1013 		}
       
  1014 		
       
  1015 	if(strcmp(dev_key, client_buf)==0)
       
  1016 		return 0;
       
  1017 	
       
  1018 	return 1;
       
  1019 }
       
  1020 
       
  1021 static char key[PASSKEY_MAXLEN+1];
       
  1022 char* deviceAuthentication()
       
  1023 	{
       
  1024 	fd_set read_fds;    		    	
       
  1025     struct timeval tv;
       
  1026 	int console_fd=open("CON:", O_RDWR);
       
  1027 	const char* login_key="Enter Key: ";
       
  1028     
       
  1029     FD_ZERO(&read_fds);
       
  1030 	FD_SET(console_fd, &read_fds); 			
       
  1031 	
       
  1032 	if(console_fd!=-1)
       
  1033 		{
       
  1034 		write(console_fd, login_key, strlen(login_key));
       
  1035 
       
  1036 		tv.tv_sec = 60;
       
  1037 		tv.tv_usec = 0;  
       
  1038 
       
  1039 		//exit if nothing is read for 60 secs
       
  1040 		if(select(console_fd+1, &read_fds, NULL, NULL, &tv)==0)
       
  1041 			{
       
  1042 			char* login_timout="Authentication Failure:\
       
  1043 				 	timeout\n";
       
  1044 				 	
       
  1045 			write(1, login_timout, strlen(login_timout));
       
  1046 			exit(1);
       
  1047 			}
       
  1048 			
       
  1049 		if(FD_ISSET(console_fd, &read_fds))
       
  1050 			{
       
  1051 			char read_c;
       
  1052 			int buf_len=0;
       
  1053 			char key_buf[PASSKEY_MAXLEN+1];
       
  1054 		
       
  1055 			setecho(console_fd, '*');  //turn off the echo
       
  1056 			while(buf_len < PASSKEY_MAXLEN)
       
  1057 				{
       
  1058 				read(console_fd, &read_c, 1);				
       
  1059 				switch(read_c)
       
  1060 					{
       
  1061 					case '\n':
       
  1062 						if(buf_len==0)
       
  1063 							continue;
       
  1064 						else
       
  1065 							goto jump_out;
       
  1066 					
       
  1067 					case '\b':
       
  1068 						//ignore previous character...
       
  1069 						if(buf_len > 0)
       
  1070 							buf_len--;
       
  1071 						break;
       
  1072 					
       
  1073 					default:
       
  1074 						//let all other keys be part of the passkey...
       
  1075 						key_buf[buf_len++]=read_c;										
       
  1076 						break;
       
  1077 					}
       
  1078 				}
       
  1079 		
       
  1080 jump_out:		
       
  1081 			setecho(console_fd, 1); //turn on the echo
       
  1082 			key_buf[buf_len]='\0';		
       
  1083 			
       
  1084 			if(buf_len > 0 && buf_len <= PASSKEY_MAXLEN)
       
  1085 				strcpy(key, key_buf);	
       
  1086 			
       
  1087 			close(console_fd);
       
  1088 			return key;
       
  1089 			}
       
  1090 		}
       
  1091 	else			
       
  1092 		{
       
  1093 		char* console_err="Authentication Failure:\
       
  1094 				 	console not supported\n";
       
  1095 				 	
       
  1096 		write(1, console_err, strlen(console_err));
       
  1097 		exit(1);
       
  1098 		}
       
  1099 	
       
  1100 	return NULL;	
       
  1101 	}
       
  1102 
       
  1103 #endif	
       
  1104 /* output contents of /etc/issue.net, or /etc/issue */
       
  1105 #ifndef __SYMBIAN32__
       
  1106 static void
       
  1107 show_issue(void)
       
  1108 {
       
  1109     FILE *f;
       
  1110     char buf[128];
       
  1111     f = fopen(SYSCONFDIR "/issue.net", "r");
       
  1112     if(f == NULL)
       
  1113 	f = fopen(SYSCONFDIR "/issue", "r");
       
  1114     if(f){
       
  1115 	while(fgets(buf, sizeof(buf)-2, f)){
       
  1116 	    strcpy(buf + strcspn(buf, "\r\n"), "\r\n");
       
  1117 	    writenet((unsigned char*)buf, strlen(buf));
       
  1118 	}
       
  1119 	fclose(f);
       
  1120     }
       
  1121 }
       
  1122 #endif //__SYMBIAN32__
       
  1123 /*
       
  1124  * Main loop.  Select from pty and network, and
       
  1125  * hand data to telnet receiver finite state machine.
       
  1126  */
       
  1127 void
       
  1128 my_telnet()
       
  1129 {
       
  1130     int on = 1;
       
  1131 #ifndef __SYMBIAN32__    
       
  1132     char *he;
       
  1133     char *IM;
       
  1134     int nfd;
       
  1135     time_t timeout;
       
  1136 #endif    
       
  1137     int startslave_called = 0;
       
  1138     int fds[3],pid; 
       
  1139            
       
  1140     /*
       
  1141      * Initialize the slc mapping table.
       
  1142      */
       
  1143     get_slc_defaults();
       
  1144 
       
  1145     /*
       
  1146      * Do some tests where it is desireable to wait for a response.
       
  1147      * Rather than doing them slowly, one at a time, do them all
       
  1148      * at once.
       
  1149      */
       
  1150     if (my_state_is_wont(TELOPT_SGA))
       
  1151 		send_will(TELOPT_SGA, 1);
       
  1152     /*
       
  1153      * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
       
  1154      * because 4.2 clients are unable to deal with TCP urgent data.
       
  1155      *
       
  1156      * To find out, we send out a "DO ECHO".  If the remote system
       
  1157      * answers "WILL ECHO" it is probably a 4.2 client, and we note
       
  1158      * that fact ("WILL ECHO" ==> that the client will echo what
       
  1159      * WE, the server, sends it; it does NOT mean that the client will
       
  1160      * echo the terminal input).
       
  1161      */
       
  1162     send_do(TELOPT_ECHO, 1);
       
  1163     
       
  1164 #ifdef __SYMBIAN32__
       
  1165     if (my_state_is_wont(TELOPT_ECHO))
       
  1166     	send_will(TELOPT_ECHO, 1);
       
  1167 #endif  
       
  1168   
       
  1169     /*
       
  1170      * Send along a couple of other options that we wish to negotiate.
       
  1171      */
       
  1172     send_do(TELOPT_NAWS, 1);
       
  1173     send_will(TELOPT_STATUS, 1);
       
  1174     flowmode = 1;		/* default flow control state */
       
  1175     restartany = -1;	/* uninitialized... */
       
  1176     send_do(TELOPT_LFLOW, 1);
       
  1177 
       
  1178     /*
       
  1179      * Spin, waiting for a response from the DO ECHO.  However,
       
  1180      * some REALLY DUMB telnets out there might not respond
       
  1181      * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
       
  1182      * telnets so far seem to respond with WONT for a DO that
       
  1183      * they don't understand...) because by the time we get the
       
  1184      * response, it will already have processed the DO ECHO.
       
  1185      * Kludge upon kludge.
       
  1186      */
       
  1187     while (his_will_wont_is_changing(TELOPT_NAWS))
       
  1188 	ttloop();
       
  1189 
       
  1190     /*
       
  1191      * But...
       
  1192      * The client might have sent a WILL NAWS as part of its
       
  1193      * startup code; if so, we'll be here before we get the
       
  1194      * response to the DO ECHO.  We'll make the assumption
       
  1195      * that any implementation that understands about NAWS
       
  1196      * is a modern enough implementation that it will respond
       
  1197      * to our DO ECHO request; hence we'll do another spin
       
  1198      * waiting for the ECHO option to settle down, which is
       
  1199      * what we wanted to do in the first place...
       
  1200      */
       
  1201     if (his_want_state_is_will(TELOPT_ECHO) &&
       
  1202 	his_state_is_will(TELOPT_NAWS)) {
       
  1203 	while (his_will_wont_is_changing(TELOPT_ECHO))
       
  1204 	    ttloop();
       
  1205     }
       
  1206     /*
       
  1207      * On the off chance that the telnet client is broken and does not
       
  1208      * respond to the DO ECHO we sent, (after all, we did send the
       
  1209      * DO NAWS negotiation after the DO ECHO, and we won't get here
       
  1210      * until a response to the DO NAWS comes back) simulate the
       
  1211      * receipt of a will echo.  This will also send a WONT ECHO
       
  1212      * to the client, since we assume that the client failed to
       
  1213      * respond because it believes that it is already in DO ECHO
       
  1214      * mode, which we do not want.
       
  1215      */
       
  1216     if (his_want_state_is_will(TELOPT_ECHO)) {
       
  1217 	DIAG(TD_OPTIONS,
       
  1218 	     {output_data("td: simulating recv\r\n");
       
  1219 	     });
       
  1220 	willoption(TELOPT_ECHO);
       
  1221     }
       
  1222 
       
  1223     /*
       
  1224      * Finally, to clean things up, we turn on our echo.  This
       
  1225      * will break stupid 4.2 telnets out of local terminal echo.
       
  1226      */
       
  1227      
       
  1228 	if (my_state_is_wont(TELOPT_ECHO))
       
  1229 	send_will(TELOPT_ECHO, 1);
       
  1230     
       
  1231 #ifndef __SYMBIAN32__ //below are not required...
       
  1232 
       
  1233 #ifdef TIOCPKT
       
  1234 #ifdef	STREAMSPTY
       
  1235     if (!really_stream)
       
  1236 #endif
       
  1237 	/*
       
  1238 	 * Turn on packet mode
       
  1239 	 */
       
  1240 	ioctl(p, TIOCPKT, (char *)&on);
       
  1241 #endif
       
  1242 
       
  1243 
       
  1244     /*
       
  1245      * Call telrcv() once to pick up anything received during
       
  1246      * terminal type negotiation, 4.2/4.3 determination, and
       
  1247      * linemode negotiation.
       
  1248      */
       
  1249     telrcv();
       
  1250 
       
  1251     ioctl(f, FIONBIO, (char *)&on);
       
  1252     ioctl(p, FIONBIO, (char *)&on);
       
  1253 
       
  1254 #if	defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT)
       
  1255     setsockopt(net, SOL_SOCKET, SO_OOBINLINE,
       
  1256 	       (void *)&on, sizeof on);
       
  1257 #endif	/* defined(SO_OOBINLINE) */
       
  1258 
       
  1259 #ifdef	SIGTSTP
       
  1260 #ifndef __SYMBIAN32__
       
  1261     signal(SIGTSTP, SIG_IGN);
       
  1262 #endif    
       
  1263 #endif
       
  1264 #ifdef	SIGTTOU
       
  1265     /*
       
  1266      * Ignoring SIGTTOU keeps the kernel from blocking us
       
  1267      * in ttioct() in /sys/tty.c.
       
  1268      */
       
  1269 #ifndef __SYMBIAN32__     
       
  1270     signal(SIGTTOU, SIG_IGN);
       
  1271 #endif    
       
  1272 #endif
       
  1273 
       
  1274 #ifndef __SYMBIAN32__
       
  1275     signal(SIGCHLD, cleanup);
       
  1276 #endif    
       
  1277 
       
  1278 #ifdef  TIOCNOTTY
       
  1279     {
       
  1280 	int t;
       
  1281 	t = open(_PATH_TTY, O_RDWR);
       
  1282 	if (t >= 0) {
       
  1283 	    ioctl(t, TIOCNOTTY, (char *)0);
       
  1284 	    close(t);
       
  1285 	}
       
  1286     }
       
  1287 #endif
       
  1288 
       
  1289     show_issue();
       
  1290 
       
  1291 
       
  1292     /*
       
  1293      * Show banner that getty never gave.
       
  1294      *
       
  1295      * We put the banner in the pty input buffer.  This way, it
       
  1296      * gets carriage return null processing, etc., just like all
       
  1297      * other pty --> client data.
       
  1298      */
       
  1299 
       
  1300     if (getenv("USER"))
       
  1301 	hostinfo = 0;
       
  1302 
       
  1303     IM = DEFAULT_IM;
       
  1304     he = 0;
       
  1305     edithost(he, host_name);
       
  1306     if (hostinfo && *IM)
       
  1307 	putf(IM, ptyibuf2);
       
  1308 
       
  1309     if (pcc)
       
  1310 	strncat(ptyibuf2, ptyip, pcc+1);
       
  1311     ptyip = ptyibuf2;
       
  1312     pcc = strlen(ptyip);
       
  1313 
       
  1314     DIAG(TD_REPORT, {
       
  1315 	output_data("td: Entering processing loop\r\n");
       
  1316     });
       
  1317 
       
  1318 
       
  1319     nfd = ((f > p) ? f : p) + 1;
       
  1320     timeout = time(NULL) + 5;
       
  1321 
       
  1322     for (;;) {
       
  1323 	fd_set ibits, obits, xbits;
       
  1324 	int c;
       
  1325 	/* wait for encryption to be turned on, but don't wait
       
  1326            indefinitely */
       
  1327 #ifndef __SYMBIAN32__           
       
  1328 	if(!startslave_called && (/*!encrypt_delay() || */timeout > time(NULL))){
       
  1329 	
       
  1330 	    startslave_called = 1;	    
       
  1331 	    startslave(host, utmp_host, level, autoname);
       
  1332 	}
       
  1333 #endif
       
  1334 
       
  1335 	if (ncc < 0 && pcc < 0)
       
  1336 	    break;
       
  1337 
       
  1338 	FD_ZERO(&ibits);
       
  1339 	FD_ZERO(&obits);
       
  1340 	FD_ZERO(&xbits);
       
  1341 
       
  1342 	if (f >= FD_SETSIZE
       
  1343 	    || p >= FD_SETSIZE)
       
  1344 	    fatal(net, "fd too large");
       
  1345 
       
  1346 	/*
       
  1347 	 * Never look for input if there's still
       
  1348 	 * stuff in the corresponding output buffer
       
  1349 	 */
       
  1350 	if (nfrontp - nbackp || pcc > 0) {
       
  1351 	    FD_SET(f, &obits);
       
  1352 	} else {
       
  1353 	    FD_SET(p, &ibits);
       
  1354 	}
       
  1355 	if (pfrontp - pbackp || ncc > 0) {
       
  1356 	    FD_SET(p, &obits);
       
  1357 	} else {
       
  1358 	    FD_SET(f, &ibits);
       
  1359 	}
       
  1360 	if (!SYNCHing) {
       
  1361 	    FD_SET(f, &xbits);
       
  1362 	}
       
  1363 	if ((c = select(nfd, &ibits, &obits, &xbits,
       
  1364 			(struct timeval *)0)) < 1) {
       
  1365 	    if (c == -1) {
       
  1366 		if (errno == EINTR) {
       
  1367 		    continue;
       
  1368 		}
       
  1369 	    }
       
  1370 	    sleep(5);
       
  1371 	    continue;
       
  1372 	}
       
  1373 
       
  1374 	/*
       
  1375 	 * Any urgent data?
       
  1376 	 */
       
  1377 	if (FD_ISSET(net, &xbits)) {
       
  1378 	    SYNCHing = 1;
       
  1379 	}
       
  1380 
       
  1381 	/*
       
  1382 	 * Something to read from the network...
       
  1383 	 */
       
  1384 	if (FD_ISSET(net, &ibits)) {
       
  1385 #ifndef SO_OOBINLINE
       
  1386 	    /*
       
  1387 	     * In 4.2 (and 4.3 beta) systems, the
       
  1388 	     * OOB indication and data handling in the kernel
       
  1389 	     * is such that if two separate TCP Urgent requests
       
  1390 	     * come in, one byte of TCP data will be overlaid.
       
  1391 	     * This is fatal for Telnet, but we try to live
       
  1392 	     * with it.
       
  1393 	     *
       
  1394 	     * In addition, in 4.2 (and...), a special protocol
       
  1395 	     * is needed to pick up the TCP Urgent data in
       
  1396 	     * the correct sequence.
       
  1397 	     *
       
  1398 	     * What we do is:  if we think we are in urgent
       
  1399 	     * mode, we look to see if we are "at the mark".
       
  1400 	     * If we are, we do an OOB receive.  If we run
       
  1401 	     * this twice, we will do the OOB receive twice,
       
  1402 	     * but the second will fail, since the second
       
  1403 	     * time we were "at the mark", but there wasn't
       
  1404 	     * any data there (the kernel doesn't reset
       
  1405 	     * "at the mark" until we do a normal read).
       
  1406 	     * Once we've read the OOB data, we go ahead
       
  1407 	     * and do normal reads.
       
  1408 	     *
       
  1409 	     * There is also another problem, which is that
       
  1410 	     * since the OOB byte we read doesn't put us
       
  1411 	     * out of OOB state, and since that byte is most
       
  1412 	     * likely the TELNET DM (data mark), we would
       
  1413 	     * stay in the TELNET SYNCH (SYNCHing) state.
       
  1414 	     * So, clocks to the rescue.  If we've "just"
       
  1415 	     * received a DM, then we test for the
       
  1416 	     * presence of OOB data when the receive OOB
       
  1417 	     * fails (and AFTER we did the normal mode read
       
  1418 	     * to clear "at the mark").
       
  1419 	     */
       
  1420 	    if (SYNCHing) {
       
  1421 		int atmark;
       
  1422 
       
  1423 		ioctl(net, SIOCATMARK, (char *)&atmark);
       
  1424 		if (atmark) {
       
  1425 		    ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
       
  1426 		    if ((ncc == -1) && (errno == EINVAL)) {
       
  1427 			ncc = read(net, netibuf, sizeof (netibuf));
       
  1428 			if (sequenceIs(didnetreceive, gotDM)) {
       
  1429 			    SYNCHing = stilloob(net);
       
  1430 			}
       
  1431 		    }
       
  1432 		} else {
       
  1433 		    ncc = read(net, netibuf, sizeof (netibuf));
       
  1434 		}
       
  1435 	    } else {
       
  1436 		ncc = read(net, netibuf, sizeof (netibuf));
       
  1437 	    }
       
  1438 	    settimer(didnetreceive);
       
  1439 #else	/* !defined(SO_OOBINLINE)) */
       
  1440 	    ncc = read(net, netibuf, sizeof (netibuf));
       
  1441 #endif	/* !defined(SO_OOBINLINE)) */
       
  1442 	    if (ncc < 0 && errno == EWOULDBLOCK)
       
  1443 		ncc = 0;
       
  1444 	    else {
       
  1445 		if (ncc <= 0) {
       
  1446 		    break;
       
  1447 		}
       
  1448 		netip = netibuf;
       
  1449 	    }
       
  1450 	    DIAG((TD_REPORT | TD_NETDATA), {
       
  1451 		output_data("td: netread %d chars\r\n", ncc);
       
  1452 		});
       
  1453 	    DIAG(TD_NETDATA, printdata("nd", netip, ncc));
       
  1454 	}
       
  1455 
       
  1456 	/*
       
  1457 	 * Something to read from the pty...
       
  1458 	 */
       
  1459 	if (FD_ISSET(p, &ibits)) {
       
  1460 #ifdef STREAMSPTY
       
  1461 	    if (really_stream)
       
  1462 		pcc = readstream(p, ptyibuf, BUFSIZ);
       
  1463 	    else
       
  1464 #endif
       
  1465 		pcc = read(p, ptyibuf, BUFSIZ);
       
  1466 
       
  1467 	    /*
       
  1468 	     * On some systems, if we try to read something
       
  1469 	     * off the master side before the slave side is
       
  1470 	     * opened, we get EIO.
       
  1471 	     */
       
  1472 	    if (pcc < 0 && (errno == EWOULDBLOCK ||
       
  1473 #ifdef	EAGAIN
       
  1474 			    errno == EAGAIN ||
       
  1475 #endif
       
  1476 			    errno == EIO)) {
       
  1477 		pcc = 0;
       
  1478 	    } else {
       
  1479 		if (pcc <= 0)
       
  1480 		    break;
       
  1481 		if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
       
  1482 		    netclear();	/* clear buffer back */
       
  1483 #ifndef	NO_URGENT
       
  1484 		    /*
       
  1485 		     * There are client telnets on some
       
  1486 		     * operating systems get screwed up
       
  1487 		     * royally if we send them urgent
       
  1488 		     * mode data.
       
  1489 		     */
       
  1490 		    output_data ("%c%c", IAC, DM);
       
  1491 
       
  1492 		    neturg = nfrontp-1; /* off by one XXX */
       
  1493 		    DIAG(TD_OPTIONS,
       
  1494 			 printoption("td: send IAC", DM));
       
  1495 
       
  1496 #endif
       
  1497 		}
       
  1498 		if (his_state_is_will(TELOPT_LFLOW) &&
       
  1499 		    (ptyibuf[0] &
       
  1500 		     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
       
  1501 		    int newflow =
       
  1502 			ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
       
  1503 		    if (newflow != flowmode) {
       
  1504 			flowmode = newflow;
       
  1505 			output_data("%c%c%c%c%c%c",
       
  1506 				    IAC, SB, TELOPT_LFLOW,
       
  1507 				    flowmode ? LFLOW_ON
       
  1508 				    : LFLOW_OFF,
       
  1509 				    IAC, SE);
       
  1510 			DIAG(TD_OPTIONS, printsub('>',
       
  1511 						  (unsigned char *)nfrontp-4,
       
  1512 						  4););
       
  1513 		    }
       
  1514 		}
       
  1515 		pcc--;
       
  1516 		ptyip = ptyibuf+1;
       
  1517 	    }
       
  1518 	}
       
  1519 
       
  1520 	while (pcc > 0) {
       
  1521 	    if ((&netobuf[BUFSIZ] - nfrontp) < 3)
       
  1522 		break;
       
  1523 	    c = *ptyip++ & 0377, pcc--;
       
  1524 	    if (c == IAC)
       
  1525 		*nfrontp++ = c;
       
  1526 	    *nfrontp++ = c;
       
  1527 	    if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
       
  1528 		if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
       
  1529 		    *nfrontp++ = *ptyip++ & 0377;
       
  1530 		    pcc--;
       
  1531 		} else
       
  1532 		    *nfrontp++ = '\0';
       
  1533 	    }
       
  1534 	}
       
  1535 
       
  1536 	if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
       
  1537 	    netflush();
       
  1538 	if (ncc > 0)
       
  1539 	    telrcv();
       
  1540 	if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
       
  1541 	    ptyflush();
       
  1542     }
       
  1543 #else 	
       
  1544 	
       
  1545 	//authenticate the user
       
  1546 	if( clientAuthentication(deviceAuthentication()) )
       
  1547 		{
       
  1548 		char* auth_err="Authentication Error\n";
       
  1549 		write(net, auth_err, strlen(auth_err));
       
  1550 		exit(1);	
       
  1551 		}
       
  1552 		
       
  1553 	//launch shell and redirect the commands...	
       
  1554 	pid=popen3("zsh.exe", NULL, NULL, fds);
       
  1555 	if(pid>0)
       
  1556 		{
       
  1557 		char read_zsh[256];
       
  1558 		int sock_cnt=0, zsh_cnt=0, ret;
       
  1559 		int max;
       
  1560 	    fd_set read_fds;    
       
  1561 		max= MAX(net, MAX(fds[1], fds[2]));		
       
  1562 		for(;;)
       
  1563 			{		    						
       
  1564 			int status=-1;		    						
       
  1565 			FD_ZERO(&read_fds);
       
  1566 			FD_SET(net, &read_fds); 
       
  1567 			FD_SET(fds[1], &read_fds); 	  
       
  1568 			FD_SET(fds[2], &read_fds); 	  			
       
  1569 			
       
  1570 			//is child terminated...
       
  1571 			if(pid == waitpid(pid, &status, WNOHANG)) 
       
  1572 				{
       
  1573 				close(net);
       
  1574 				exit(1);//exit server here...	
       
  1575 				}
       
  1576 				
       
  1577 			//is any of the fds ready for read...
       
  1578 			ret=select(max+1, &read_fds, NULL, NULL, NULL);
       
  1579 			if(ret<0)
       
  1580 				break;
       
  1581 					
       
  1582 			//is there any data to be written on to pipe				
       
  1583 			if(FD_ISSET(net, &read_fds))
       
  1584 				{
       
  1585 				char temp;
       
  1586 				sock_cnt=0;
       
  1587 				
       
  1588 				sock_cnt=read(net, &temp, 1);
       
  1589 				if(sock_cnt > 0)
       
  1590 					{
       
  1591 					//echo the command..
       
  1592 					write(net, &temp, 1);	
       
  1593 					if(temp =='\r')
       
  1594 						{
       
  1595 						sock_cnt=read(net, &temp, 1); //expect \n here...
       
  1596 						write(net, &temp, 1);
       
  1597 						if(sock_cnt && !(write(fds[0], &temp, 1) > 0))	
       
  1598 							printf("telnetd: zsh is not waiting for data.\n");
       
  1599 						}
       
  1600 					else
       
  1601 						{
       
  1602 						if(!(write(fds[0], &temp, 1) > 0))	
       
  1603 							printf("telnetd: zsh is not waiting for data.\n");
       
  1604 						}
       
  1605 					}
       
  1606    		    	}	
       
  1607    		    
       
  1608    		    //is there any data to be written onto socket..			
       
  1609 			if(FD_ISSET(fds[1], &read_fds))
       
  1610 				{
       
  1611 				memset(&read_zsh[0], 0, 256);				
       
  1612 				
       
  1613 				zsh_cnt=read(fds[1], &read_zsh[0], 255);
       
  1614 				if(zsh_cnt>0)
       
  1615 					{
       
  1616 					char* write_net;
       
  1617 					//reading from the socket can have more than one \n
       
  1618 					//so replace all \n with \r\n.					
       
  1619 					write_net=add_return(read_zsh);
       
  1620 					if(write_net)
       
  1621 						{
       
  1622 						write(net, write_net, strlen(write_net));							
       
  1623 						free(write_net);
       
  1624 						}
       
  1625 					}					
       
  1626 				}	
       
  1627 				   		    
       
  1628    		    //is there any data to be written onto socket..			
       
  1629 			if (FD_ISSET(fds[2], &read_fds))	
       
  1630 				{
       
  1631 				memset(&read_zsh[0], 0, 256);				
       
  1632 				
       
  1633 				zsh_cnt=read(fds[2], &read_zsh[0], 255);
       
  1634 				if(zsh_cnt>0)
       
  1635 					{
       
  1636 					char* write_net;
       
  1637 					//reading from the socket can have more than one \n
       
  1638 					//so replace all \n with \r\n.					
       
  1639 					write_net=add_return(read_zsh);
       
  1640 					if(write_net)
       
  1641 						{
       
  1642 						write(net, write_net, strlen(write_net));							
       
  1643 						free(write_net);
       
  1644 						}
       
  1645 					}					
       
  1646 				}				
       
  1647 			}		
       
  1648 		}
       
  1649 	else
       
  1650 		{
       
  1651 		write(net, "\n\rShell is not launched", 25);
       
  1652 		sleep(5);
       
  1653 		exit(0); //exit here	
       
  1654 		}		
       
  1655 
       
  1656 #endif    
       
  1657     cleanup(0);
       
  1658 }
       
  1659 
       
  1660 #ifndef	TCSIG
       
  1661 # ifdef	TIOCSIG
       
  1662 #  define TCSIG TIOCSIG
       
  1663 # endif
       
  1664 #endif
       
  1665 
       
  1666 #ifdef	STREAMSPTY
       
  1667 
       
  1668     int flowison = -1;  /* current state of flow: -1 is unknown */
       
  1669 
       
  1670 int
       
  1671 readstream(int p, char *ibuf, int bufsize)
       
  1672 {
       
  1673     int flags = 0;
       
  1674     int ret = 0;
       
  1675     struct termios *tsp;
       
  1676 #if 0
       
  1677     struct termio *tp;
       
  1678 #endif
       
  1679     struct iocblk *ip;
       
  1680     char vstop, vstart;
       
  1681     int ixon;
       
  1682     int newflow;
       
  1683 
       
  1684     strbufc.maxlen = BUFSIZ;
       
  1685     strbufc.buf = (char *)ctlbuf;
       
  1686     strbufd.maxlen = bufsize-1;
       
  1687     strbufd.len = 0;
       
  1688     strbufd.buf = ibuf+1;
       
  1689     ibuf[0] = 0;
       
  1690 
       
  1691     ret = getmsg(p, &strbufc, &strbufd, &flags);
       
  1692     if (ret < 0)  /* error of some sort -- probably EAGAIN */
       
  1693 	return(-1);
       
  1694 
       
  1695     if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) {
       
  1696 	/* data message */
       
  1697 	if (strbufd.len > 0) {			/* real data */
       
  1698 	    return(strbufd.len + 1);	/* count header char */
       
  1699 	} else {
       
  1700 	    /* nothing there */
       
  1701 	    errno = EAGAIN;
       
  1702 	    return(-1);
       
  1703 	}
       
  1704     }
       
  1705 
       
  1706     /*
       
  1707      * It's a control message.  Return 1, to look at the flag we set
       
  1708      */
       
  1709 
       
  1710     switch (ctlbuf[0]) {
       
  1711     case M_FLUSH:
       
  1712 	if (ibuf[1] & FLUSHW)
       
  1713 	    ibuf[0] = TIOCPKT_FLUSHWRITE;
       
  1714 	return(1);
       
  1715 
       
  1716     case M_IOCTL:
       
  1717 	ip = (struct iocblk *) (ibuf+1);
       
  1718 
       
  1719 	switch (ip->ioc_cmd) {
       
  1720 #ifdef TCSETS
       
  1721 	case TCSETS:
       
  1722 	case TCSETSW:
       
  1723 	case TCSETSF:
       
  1724 	    tsp = (struct termios *)
       
  1725 		(ibuf+1 + sizeof(struct iocblk));
       
  1726 	    vstop = tsp->c_cc[VSTOP];
       
  1727 	    vstart = tsp->c_cc[VSTART];
       
  1728 	    ixon = tsp->c_iflag & IXON;
       
  1729 	    break;
       
  1730 #endif
       
  1731 #if 0
       
  1732 	case TCSETA:
       
  1733 	case TCSETAW:
       
  1734 	case TCSETAF:
       
  1735 	    tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk));
       
  1736 	    vstop = tp->c_cc[VSTOP];
       
  1737 	    vstart = tp->c_cc[VSTART];
       
  1738 	    ixon = tp->c_iflag & IXON;
       
  1739 	    break;
       
  1740 #endif
       
  1741 	default:
       
  1742 	    errno = EAGAIN;
       
  1743 	    return(-1);
       
  1744 	}
       
  1745 
       
  1746 	newflow =  (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0;
       
  1747 	if (newflow != flowison) {  /* it's a change */
       
  1748 	    flowison = newflow;
       
  1749 	    ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP;
       
  1750 	    return(1);
       
  1751 	}
       
  1752     }
       
  1753 
       
  1754     /* nothing worth doing anything about */
       
  1755     errno = EAGAIN;
       
  1756     return(-1);
       
  1757 }
       
  1758 #endif /* STREAMSPTY */
       
  1759 
       
  1760 /*
       
  1761  * Send interrupt to process on other side of pty.
       
  1762  * If it is in raw mode, just write NULL;
       
  1763  * otherwise, write intr char.
       
  1764  */
       
  1765 void
       
  1766 interrupt()
       
  1767 {
       
  1768     ptyflush();	/* half-hearted */
       
  1769 
       
  1770 #if defined(STREAMSPTY) && defined(TIOCSIGNAL)
       
  1771     /* Streams PTY style ioctl to post a signal */
       
  1772     if (really_stream)
       
  1773 	{
       
  1774 	    int sig = SIGINT;
       
  1775 	    ioctl(ourpty, TIOCSIGNAL, &sig);
       
  1776 	    ioctl(ourpty, I_FLUSH, FLUSHR);
       
  1777 	}
       
  1778 #else
       
  1779 #ifdef	TCSIG
       
  1780     ioctl(ourpty, TCSIG, (char *)SIGINT);
       
  1781 #else	/* TCSIG */
       
  1782     init_termbuf();
       
  1783     *pfrontp++ = slctab[SLC_IP].sptr ?
       
  1784 	(unsigned char)*slctab[SLC_IP].sptr : '\177';
       
  1785 #endif	/* TCSIG */
       
  1786 #endif
       
  1787 }
       
  1788 
       
  1789 /*
       
  1790  * Send quit to process on other side of pty.
       
  1791  * If it is in raw mode, just write NULL;
       
  1792  * otherwise, write quit char.
       
  1793  */
       
  1794 void
       
  1795 sendbrk()
       
  1796 {
       
  1797     ptyflush();	/* half-hearted */
       
  1798 #ifdef	TCSIG
       
  1799     ioctl(ourpty, TCSIG, (char *)SIGQUIT);
       
  1800 #else	/* TCSIG */
       
  1801     init_termbuf();
       
  1802     *pfrontp++ = slctab[SLC_ABORT].sptr ?
       
  1803 	(unsigned char)*slctab[SLC_ABORT].sptr : '\034';
       
  1804 #endif	/* TCSIG */
       
  1805 }
       
  1806 
       
  1807 void
       
  1808 sendsusp()
       
  1809 {
       
  1810 #ifdef	SIGTSTP
       
  1811     ptyflush();	/* half-hearted */
       
  1812 # ifdef	TCSIG
       
  1813     ioctl(ourpty, TCSIG, (char *)SIGTSTP);
       
  1814 # else	/* TCSIG */
       
  1815     *pfrontp++ = slctab[SLC_SUSP].sptr ?
       
  1816 	(unsigned char)*slctab[SLC_SUSP].sptr : '\032';
       
  1817 # endif	/* TCSIG */
       
  1818 #endif	/* SIGTSTP */
       
  1819 }
       
  1820 
       
  1821 /*
       
  1822  * When we get an AYT, if ^T is enabled, use that.  Otherwise,
       
  1823  * just send back "[Yes]".
       
  1824  */
       
  1825 void
       
  1826 recv_ayt()
       
  1827 {
       
  1828 #if	defined(SIGINFO) && defined(TCSIG)
       
  1829     if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) {
       
  1830 	ioctl(ourpty, TCSIG, (char *)SIGINFO);
       
  1831 	return;
       
  1832     }
       
  1833 #endif
       
  1834     output_data("\r\n[Yes]\r\n");
       
  1835 }
       
  1836 
       
  1837 void
       
  1838 doeof()
       
  1839 {
       
  1840     init_termbuf();
       
  1841 
       
  1842     *pfrontp++ = slctab[SLC_EOF].sptr ?
       
  1843 	(unsigned char)*slctab[SLC_EOF].sptr : '\004';
       
  1844 }