1 1.60 kre /* $NetBSD: telnetd.c,v 1.60 2024/10/29 13:10:10 kre Exp $ */ 2 1.17 thorpej 3 1.16 itojun /* 4 1.16 itojun * Copyright (C) 1997 and 1998 WIDE Project. 5 1.16 itojun * All rights reserved. 6 1.16 itojun * 7 1.16 itojun * Redistribution and use in source and binary forms, with or without 8 1.16 itojun * modification, are permitted provided that the following conditions 9 1.16 itojun * are met: 10 1.16 itojun * 1. Redistributions of source code must retain the above copyright 11 1.16 itojun * notice, this list of conditions and the following disclaimer. 12 1.16 itojun * 2. Redistributions in binary form must reproduce the above copyright 13 1.16 itojun * notice, this list of conditions and the following disclaimer in the 14 1.16 itojun * documentation and/or other materials provided with the distribution. 15 1.16 itojun * 3. Neither the name of the project nor the names of its contributors 16 1.16 itojun * may be used to endorse or promote products derived from this software 17 1.16 itojun * without specific prior written permission. 18 1.16 itojun * 19 1.16 itojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 1.16 itojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.16 itojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.16 itojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 1.16 itojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.16 itojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.16 itojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.16 itojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.16 itojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.16 itojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.16 itojun * SUCH DAMAGE. 30 1.16 itojun */ 31 1.16 itojun 32 1.1 cgd /* 33 1.3 cgd * Copyright (c) 1989, 1993 34 1.3 cgd * The Regents of the University of California. All rights reserved. 35 1.1 cgd * 36 1.1 cgd * Redistribution and use in source and binary forms, with or without 37 1.1 cgd * modification, are permitted provided that the following conditions 38 1.1 cgd * are met: 39 1.1 cgd * 1. Redistributions of source code must retain the above copyright 40 1.1 cgd * notice, this list of conditions and the following disclaimer. 41 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 42 1.1 cgd * notice, this list of conditions and the following disclaimer in the 43 1.1 cgd * documentation and/or other materials provided with the distribution. 44 1.43 agc * 3. Neither the name of the University nor the names of its contributors 45 1.1 cgd * may be used to endorse or promote products derived from this software 46 1.1 cgd * without specific prior written permission. 47 1.1 cgd * 48 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 1.1 cgd * SUCH DAMAGE. 59 1.1 cgd */ 60 1.1 cgd 61 1.9 mrg #include <sys/cdefs.h> 62 1.1 cgd #ifndef lint 63 1.51 lukem __COPYRIGHT("@(#) Copyright (c) 1989, 1993\ 64 1.51 lukem The Regents of the University of California. All rights reserved."); 65 1.5 thorpej #if 0 66 1.5 thorpej static char sccsid[] = "@(#)telnetd.c 8.4 (Berkeley) 5/30/95"; 67 1.5 thorpej #else 68 1.60 kre __RCSID("$NetBSD: telnetd.c,v 1.60 2024/10/29 13:10:10 kre Exp $"); 69 1.5 thorpej #endif 70 1.1 cgd #endif /* not lint */ 71 1.1 cgd 72 1.1 cgd #include "telnetd.h" 73 1.1 cgd #include "pathnames.h" 74 1.1 cgd 75 1.9 mrg #include <arpa/inet.h> 76 1.9 mrg 77 1.16 itojun #include <err.h> 78 1.10 lukem #include <termcap.h> 79 1.9 mrg 80 1.20 ad #include <limits.h> 81 1.20 ad 82 1.39 itojun #ifdef KRB5 83 1.21 thorpej #define Authenticator k5_Authenticator 84 1.21 thorpej #include <krb5.h> 85 1.21 thorpej #undef Authenticator 86 1.52 elric #include <krb5/com_err.h> 87 1.21 thorpej #endif 88 1.21 thorpej 89 1.21 thorpej #if defined(AUTHENTICATION) || defined(ENCRYPTION) 90 1.21 thorpej #include <libtelnet/misc.h> 91 1.21 thorpej #endif 92 1.21 thorpej 93 1.25 christos extern int require_hwpreauth; 94 1.25 christos #ifdef KRB5 95 1.25 christos extern krb5_context telnet_context; 96 1.25 christos #endif 97 1.3 cgd int registerd_host_only = 0; 98 1.3 cgd 99 1.3 cgd 100 1.1 cgd /* 101 1.1 cgd * I/O data buffers, 102 1.1 cgd * pointers, and counters. 103 1.1 cgd */ 104 1.1 cgd char ptyibuf[BUFSIZ], *ptyip = ptyibuf; 105 1.1 cgd char ptyibuf2[BUFSIZ]; 106 1.1 cgd 107 1.3 cgd 108 1.1 cgd int hostinfo = 1; /* do we print login banner? */ 109 1.1 cgd 110 1.1 cgd 111 1.49 he static int debug = 0; 112 1.1 cgd int keepalive = 1; 113 1.53 christos const char *gettyname = "default"; 114 1.1 cgd char *progname; 115 1.1 cgd 116 1.54 joerg void usage(void) __dead; 117 1.46 perry int getterminaltype(char *, size_t); 118 1.53 christos int getent(char *, const char *); 119 1.54 joerg static void doit(struct sockaddr *) __dead; 120 1.46 perry void _gettermname(void); 121 1.46 perry int terminaltypeok(char *); 122 1.46 perry char *getstr(const char *, char **); 123 1.1 cgd 124 1.3 cgd /* 125 1.3 cgd * The string to pass to getopt(). We do it this way so 126 1.3 cgd * that only the actual options that we support will be 127 1.3 cgd * passed off to getopt(). 128 1.3 cgd */ 129 1.3 cgd char valid_opts[] = { 130 1.6 tls 'd', ':', 'g', ':', 'h', 'k', 'n', 'S', ':', 'u', ':', 'U', 131 1.16 itojun '4', '6', 132 1.3 cgd #ifdef AUTHENTICATION 133 1.3 cgd 'a', ':', 'X', ':', 134 1.3 cgd #endif 135 1.21 thorpej #ifdef ENCRYPTION 136 1.21 thorpej 'e', ':', 137 1.21 thorpej #endif 138 1.3 cgd #ifdef DIAGNOSTICS 139 1.3 cgd 'D', ':', 140 1.3 cgd #endif 141 1.3 cgd #ifdef LINEMODE 142 1.3 cgd 'l', 143 1.3 cgd #endif 144 1.15 dean #ifdef SECURELOGIN 145 1.3 cgd 's', 146 1.3 cgd #endif 147 1.21 thorpej #ifdef KRB5 148 1.21 thorpej 'R', ':', 'H', 149 1.21 thorpej #endif 150 1.3 cgd '\0' 151 1.3 cgd }; 152 1.3 cgd 153 1.16 itojun int family = AF_INET; 154 1.44 christos struct sockaddr_storage from; 155 1.16 itojun 156 1.9 mrg int 157 1.46 perry main(int argc, char *argv[]) 158 1.1 cgd { 159 1.56 kamil static char Xline[] = NULL16STR; 160 1.56 kamil 161 1.50 mrg socklen_t fromlen; 162 1.50 mrg int on = 1; 163 1.46 perry int ch; 164 1.1 cgd #if defined(IPPROTO_IP) && defined(IP_TOS) 165 1.1 cgd int tos = -1; 166 1.1 cgd #endif 167 1.1 cgd 168 1.56 kamil line = Xline; 169 1.56 kamil 170 1.1 cgd pfrontp = pbackp = ptyobuf; 171 1.1 cgd netip = netibuf; 172 1.1 cgd nfrontp = nbackp = netobuf; 173 1.21 thorpej #ifdef ENCRYPTION 174 1.21 thorpej nclearto = 0; 175 1.21 thorpej #endif /* ENCRYPTION */ 176 1.1 cgd 177 1.1 cgd progname = *argv; 178 1.1 cgd 179 1.1 cgd 180 1.7 enami while ((ch = getopt(argc, argv, valid_opts)) != -1) { 181 1.8 enami switch (ch) { 182 1.1 cgd 183 1.3 cgd #ifdef AUTHENTICATION 184 1.1 cgd case 'a': 185 1.1 cgd /* 186 1.1 cgd * Check for required authentication level 187 1.1 cgd */ 188 1.1 cgd if (strcmp(optarg, "debug") == 0) { 189 1.1 cgd auth_debug_mode = 1; 190 1.1 cgd } else if (strcasecmp(optarg, "none") == 0) { 191 1.1 cgd auth_level = 0; 192 1.1 cgd } else if (strcasecmp(optarg, "other") == 0) { 193 1.1 cgd auth_level = AUTH_OTHER; 194 1.1 cgd } else if (strcasecmp(optarg, "user") == 0) { 195 1.1 cgd auth_level = AUTH_USER; 196 1.1 cgd } else if (strcasecmp(optarg, "valid") == 0) { 197 1.1 cgd auth_level = AUTH_VALID; 198 1.1 cgd } else if (strcasecmp(optarg, "off") == 0) { 199 1.1 cgd /* 200 1.1 cgd * This hack turns off authentication 201 1.1 cgd */ 202 1.1 cgd auth_level = -1; 203 1.1 cgd } else { 204 1.1 cgd fprintf(stderr, 205 1.1 cgd "telnetd: unknown authorization level for -a\n"); 206 1.1 cgd } 207 1.1 cgd break; 208 1.3 cgd #endif /* AUTHENTICATION */ 209 1.1 cgd 210 1.1 cgd 211 1.1 cgd case 'd': 212 1.1 cgd if (strcmp(optarg, "ebug") == 0) { 213 1.1 cgd debug++; 214 1.1 cgd break; 215 1.1 cgd } 216 1.1 cgd usage(); 217 1.1 cgd /* NOTREACHED */ 218 1.1 cgd break; 219 1.1 cgd 220 1.1 cgd #ifdef DIAGNOSTICS 221 1.1 cgd case 'D': 222 1.1 cgd /* 223 1.1 cgd * Check for desired diagnostics capabilities. 224 1.1 cgd */ 225 1.1 cgd if (!strcmp(optarg, "report")) { 226 1.1 cgd diagnostic |= TD_REPORT|TD_OPTIONS; 227 1.1 cgd } else if (!strcmp(optarg, "exercise")) { 228 1.1 cgd diagnostic |= TD_EXERCISE; 229 1.1 cgd } else if (!strcmp(optarg, "netdata")) { 230 1.1 cgd diagnostic |= TD_NETDATA; 231 1.1 cgd } else if (!strcmp(optarg, "ptydata")) { 232 1.1 cgd diagnostic |= TD_PTYDATA; 233 1.1 cgd } else if (!strcmp(optarg, "options")) { 234 1.1 cgd diagnostic |= TD_OPTIONS; 235 1.1 cgd } else { 236 1.1 cgd usage(); 237 1.1 cgd /* NOT REACHED */ 238 1.1 cgd } 239 1.1 cgd break; 240 1.1 cgd #endif /* DIAGNOSTICS */ 241 1.1 cgd 242 1.21 thorpej #ifdef ENCRYPTION 243 1.21 thorpej case 'e': 244 1.21 thorpej if (strcmp(optarg, "debug") == 0) { 245 1.60 kre EncryptDebug(1); 246 1.21 thorpej break; 247 1.21 thorpej } 248 1.21 thorpej usage(); 249 1.21 thorpej /* NOTREACHED */ 250 1.21 thorpej break; 251 1.21 thorpej #endif /* ENCRYPTION */ 252 1.21 thorpej 253 1.6 tls case 'g': 254 1.6 tls gettyname = optarg; 255 1.6 tls break; 256 1.1 cgd 257 1.1 cgd case 'h': 258 1.1 cgd hostinfo = 0; 259 1.1 cgd break; 260 1.1 cgd 261 1.21 thorpej #ifdef KRB5 262 1.21 thorpej case 'H': 263 1.21 thorpej { 264 1.21 thorpej require_hwpreauth = 1; 265 1.21 thorpej break; 266 1.21 thorpej } 267 1.21 thorpej #endif /* KRB5 */ 268 1.21 thorpej 269 1.1 cgd 270 1.1 cgd #ifdef LINEMODE 271 1.1 cgd case 'l': 272 1.1 cgd alwayslinemode = 1; 273 1.1 cgd break; 274 1.1 cgd #endif /* LINEMODE */ 275 1.1 cgd 276 1.3 cgd case 'k': 277 1.3 cgd #if defined(LINEMODE) && defined(KLUDGELINEMODE) 278 1.3 cgd lmodetype = NO_AUTOKLUDGE; 279 1.3 cgd #else 280 1.3 cgd /* ignore -k option if built without kludge linemode */ 281 1.3 cgd #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 282 1.3 cgd break; 283 1.3 cgd 284 1.1 cgd case 'n': 285 1.1 cgd keepalive = 0; 286 1.1 cgd break; 287 1.1 cgd 288 1.1 cgd 289 1.21 thorpej #ifdef KRB5 290 1.21 thorpej case 'R': 291 1.21 thorpej { 292 1.21 thorpej krb5_error_code retval; 293 1.21 thorpej 294 1.21 thorpej if (telnet_context == 0) { 295 1.21 thorpej retval = krb5_init_context(&telnet_context); 296 1.21 thorpej if (retval) { 297 1.21 thorpej com_err("telnetd", retval, 298 1.21 thorpej "while initializing krb5"); 299 1.21 thorpej exit(1); 300 1.21 thorpej } 301 1.21 thorpej } 302 1.21 thorpej krb5_set_default_realm(telnet_context, optarg); 303 1.21 thorpej break; 304 1.21 thorpej } 305 1.21 thorpej #endif /* KRB5 */ 306 1.21 thorpej 307 1.15 dean #ifdef SECURELOGIN 308 1.1 cgd case 's': 309 1.15 dean /* Secure login required */ 310 1.15 dean require_secure_login = 1; 311 1.1 cgd break; 312 1.15 dean #endif /* SECURELOGIN */ 313 1.1 cgd case 'S': 314 1.1 cgd fprintf(stderr, "%s%s\n", "TOS option unavailable; ", 315 1.1 cgd "-S flag not supported\n"); 316 1.1 cgd break; 317 1.1 cgd 318 1.3 cgd case 'u': 319 1.33 christos fprintf(stderr, "telnetd: -u option unneeded\n"); 320 1.3 cgd break; 321 1.3 cgd 322 1.3 cgd case 'U': 323 1.3 cgd registerd_host_only = 1; 324 1.3 cgd break; 325 1.3 cgd 326 1.3 cgd #ifdef AUTHENTICATION 327 1.1 cgd case 'X': 328 1.1 cgd /* 329 1.1 cgd * Check for invalid authentication types 330 1.1 cgd */ 331 1.1 cgd auth_disable_name(optarg); 332 1.1 cgd break; 333 1.3 cgd #endif /* AUTHENTICATION */ 334 1.1 cgd 335 1.16 itojun case '4': 336 1.16 itojun family = AF_INET; 337 1.16 itojun break; 338 1.18 thorpej 339 1.16 itojun case '6': 340 1.16 itojun family = AF_INET6; 341 1.16 itojun break; 342 1.18 thorpej 343 1.1 cgd default: 344 1.3 cgd fprintf(stderr, "telnetd: %c: unknown option\n", ch); 345 1.1 cgd /* FALLTHROUGH */ 346 1.1 cgd case '?': 347 1.1 cgd usage(); 348 1.1 cgd /* NOTREACHED */ 349 1.1 cgd } 350 1.1 cgd } 351 1.1 cgd 352 1.1 cgd argc -= optind; 353 1.1 cgd argv += optind; 354 1.1 cgd 355 1.1 cgd if (debug) { 356 1.50 mrg int s, ns, error; 357 1.50 mrg socklen_t foo; 358 1.53 christos const char *service = "telnet"; 359 1.16 itojun struct addrinfo hints, *res; 360 1.1 cgd 361 1.1 cgd if (argc > 1) { 362 1.1 cgd usage(); 363 1.1 cgd /* NOT REACHED */ 364 1.16 itojun } else if (argc == 1) 365 1.16 itojun service = *argv; 366 1.16 itojun 367 1.16 itojun memset(&hints, 0, sizeof(hints)); 368 1.16 itojun hints.ai_flags = AI_PASSIVE; 369 1.16 itojun hints.ai_family = family; 370 1.16 itojun hints.ai_socktype = SOCK_STREAM; 371 1.16 itojun hints.ai_protocol = 0; 372 1.16 itojun error = getaddrinfo(NULL, service, &hints, &res); 373 1.16 itojun 374 1.16 itojun if (error) { 375 1.22 itojun fprintf(stderr, "tcp/%s: %s\n", service, gai_strerror(error)); 376 1.22 itojun exit(1); 377 1.1 cgd } 378 1.1 cgd 379 1.16 itojun s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 380 1.1 cgd if (s < 0) { 381 1.28 wiz perror("telnetd: socket"); 382 1.22 itojun exit(1); 383 1.1 cgd } 384 1.3 cgd (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 385 1.3 cgd (char *)&on, sizeof(on)); 386 1.16 itojun if (bind(s, res->ai_addr, res->ai_addrlen) < 0) { 387 1.1 cgd perror("bind"); 388 1.1 cgd exit(1); 389 1.1 cgd } 390 1.1 cgd if (listen(s, 1) < 0) { 391 1.1 cgd perror("listen"); 392 1.1 cgd exit(1); 393 1.1 cgd } 394 1.16 itojun foo = res->ai_addrlen; 395 1.16 itojun ns = accept(s, res->ai_addr, &foo); 396 1.1 cgd if (ns < 0) { 397 1.1 cgd perror("accept"); 398 1.1 cgd exit(1); 399 1.1 cgd } 400 1.1 cgd (void) dup2(ns, 0); 401 1.1 cgd (void) close(ns); 402 1.1 cgd (void) close(s); 403 1.59 shm freeaddrinfo(res); 404 1.1 cgd } else if (argc > 0) { 405 1.1 cgd usage(); 406 1.1 cgd /* NOT REACHED */ 407 1.1 cgd } 408 1.1 cgd 409 1.24 lukem openlog("telnetd", LOG_PID, LOG_DAEMON); 410 1.1 cgd fromlen = sizeof (from); 411 1.1 cgd if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 412 1.1 cgd fprintf(stderr, "%s: ", progname); 413 1.1 cgd perror("getpeername"); 414 1.1 cgd _exit(1); 415 1.1 cgd } 416 1.1 cgd if (keepalive && 417 1.3 cgd setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, 418 1.3 cgd (char *)&on, sizeof (on)) < 0) { 419 1.1 cgd syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 420 1.1 cgd } 421 1.1 cgd 422 1.1 cgd #if defined(IPPROTO_IP) && defined(IP_TOS) 423 1.19 itojun if (((struct sockaddr *)&from)->sa_family == AF_INET) { 424 1.1 cgd if (tos < 0) 425 1.1 cgd tos = 020; /* Low Delay bit */ 426 1.1 cgd if (tos 427 1.3 cgd && (setsockopt(0, IPPROTO_IP, IP_TOS, 428 1.3 cgd (char *)&tos, sizeof(tos)) < 0) 429 1.1 cgd && (errno != ENOPROTOOPT) ) 430 1.1 cgd syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 431 1.1 cgd } 432 1.1 cgd #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ 433 1.16 itojun 434 1.1 cgd net = 0; 435 1.16 itojun doit((struct sockaddr *)&from); 436 1.1 cgd /* NOTREACHED */ 437 1.9 mrg #ifdef __GNUC__ 438 1.9 mrg exit(0); 439 1.9 mrg #endif 440 1.1 cgd } /* end of main */ 441 1.1 cgd 442 1.39 itojun void 443 1.46 perry usage(void) 444 1.1 cgd { 445 1.1 cgd fprintf(stderr, "Usage: telnetd"); 446 1.3 cgd #ifdef AUTHENTICATION 447 1.3 cgd fprintf(stderr, " [-a (debug|other|user|valid|off|none)]\n\t"); 448 1.1 cgd #endif 449 1.1 cgd fprintf(stderr, " [-debug]"); 450 1.1 cgd #ifdef DIAGNOSTICS 451 1.1 cgd fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t"); 452 1.1 cgd #endif 453 1.31 wiz #ifdef ENCRYPTION 454 1.1 cgd fprintf(stderr, " [-edebug]"); 455 1.1 cgd #endif 456 1.1 cgd fprintf(stderr, " [-h]"); 457 1.3 cgd #if defined(LINEMODE) && defined(KLUDGELINEMODE) 458 1.3 cgd fprintf(stderr, " [-k]"); 459 1.3 cgd #endif 460 1.1 cgd #ifdef LINEMODE 461 1.1 cgd fprintf(stderr, " [-l]"); 462 1.1 cgd #endif 463 1.1 cgd fprintf(stderr, " [-n]"); 464 1.3 cgd fprintf(stderr, "\n\t"); 465 1.15 dean #ifdef SECURELOGIN 466 1.1 cgd fprintf(stderr, " [-s]"); 467 1.1 cgd #endif 468 1.3 cgd #ifdef AUTHENTICATION 469 1.1 cgd fprintf(stderr, " [-X auth-type]"); 470 1.1 cgd #endif 471 1.3 cgd fprintf(stderr, " [-u utmp_hostname_length] [-U]"); 472 1.1 cgd fprintf(stderr, " [port]\n"); 473 1.1 cgd exit(1); 474 1.1 cgd } 475 1.1 cgd 476 1.1 cgd /* 477 1.1 cgd * getterminaltype 478 1.1 cgd * 479 1.1 cgd * Ask the other end to send along its terminal type and speed. 480 1.1 cgd * Output is the variable terminaltype filled in. 481 1.1 cgd */ 482 1.3 cgd static unsigned char ttytype_sbbuf[] = { 483 1.3 cgd IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE 484 1.3 cgd }; 485 1.1 cgd 486 1.39 itojun int 487 1.46 perry getterminaltype(char *name, size_t l) 488 1.1 cgd { 489 1.1 cgd int retval = -1; 490 1.1 cgd 491 1.1 cgd settimer(baseline); 492 1.39 itojun #ifdef AUTHENTICATION 493 1.1 cgd /* 494 1.1 cgd * Handle the Authentication option before we do anything else. 495 1.1 cgd */ 496 1.60 kre if (auth_level >= 0) { 497 1.60 kre send_do(TELOPT_AUTHENTICATION, 1); 498 1.60 kre while (his_will_wont_is_changing(TELOPT_AUTHENTICATION)) 499 1.60 kre ttloop(); 500 1.60 kre if (his_state_is_will(TELOPT_AUTHENTICATION)) { 501 1.60 kre retval = auth_wait(name, l); 502 1.60 kre } 503 1.1 cgd } 504 1.1 cgd #endif 505 1.1 cgd 506 1.21 thorpej #ifdef ENCRYPTION 507 1.21 thorpej send_will(TELOPT_ENCRYPT, 1); 508 1.21 thorpej #endif /* ENCRYPTION */ 509 1.1 cgd send_do(TELOPT_TTYPE, 1); 510 1.1 cgd send_do(TELOPT_TSPEED, 1); 511 1.1 cgd send_do(TELOPT_XDISPLOC, 1); 512 1.3 cgd send_do(TELOPT_NEW_ENVIRON, 1); 513 1.3 cgd send_do(TELOPT_OLD_ENVIRON, 1); 514 1.1 cgd while ( 515 1.21 thorpej #ifdef ENCRYPTION 516 1.21 thorpej his_do_dont_is_changing(TELOPT_ENCRYPT) || 517 1.21 thorpej #endif /* ENCRYPTION */ 518 1.1 cgd his_will_wont_is_changing(TELOPT_TTYPE) || 519 1.1 cgd his_will_wont_is_changing(TELOPT_TSPEED) || 520 1.1 cgd his_will_wont_is_changing(TELOPT_XDISPLOC) || 521 1.3 cgd his_will_wont_is_changing(TELOPT_NEW_ENVIRON) || 522 1.3 cgd his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) { 523 1.1 cgd ttloop(); 524 1.1 cgd } 525 1.1 cgd if (his_state_is_will(TELOPT_TSPEED)) { 526 1.3 cgd static unsigned char sb[] = 527 1.3 cgd { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE }; 528 1.1 cgd 529 1.27 wiz output_datalen((const char *)sb, sizeof sb); 530 1.4 jtk DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); 531 1.1 cgd } 532 1.21 thorpej #ifdef ENCRYPTION 533 1.21 thorpej /* 534 1.21 thorpej * Wait for the negotiation of what type of encryption we can 535 1.21 thorpej * send with. If autoencrypt is not set, this will just return. 536 1.21 thorpej */ 537 1.21 thorpej if (his_state_is_will(TELOPT_ENCRYPT)) { 538 1.21 thorpej encrypt_wait(); 539 1.21 thorpej } 540 1.21 thorpej #endif /* ENCRYPTION */ 541 1.1 cgd if (his_state_is_will(TELOPT_XDISPLOC)) { 542 1.3 cgd static unsigned char sb[] = 543 1.3 cgd { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE }; 544 1.3 cgd 545 1.27 wiz output_datalen((const char *)sb, sizeof sb); 546 1.4 jtk DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); 547 1.3 cgd } 548 1.3 cgd if (his_state_is_will(TELOPT_NEW_ENVIRON)) { 549 1.3 cgd static unsigned char sb[] = 550 1.3 cgd { IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE }; 551 1.1 cgd 552 1.27 wiz output_datalen((const char *)sb, sizeof sb); 553 1.4 jtk DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); 554 1.1 cgd } 555 1.3 cgd else if (his_state_is_will(TELOPT_OLD_ENVIRON)) { 556 1.3 cgd static unsigned char sb[] = 557 1.3 cgd { IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE }; 558 1.1 cgd 559 1.27 wiz output_datalen((const char *)sb, sizeof sb); 560 1.4 jtk DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); 561 1.1 cgd } 562 1.1 cgd if (his_state_is_will(TELOPT_TTYPE)) { 563 1.1 cgd 564 1.27 wiz output_datalen((const char *)ttytype_sbbuf, sizeof ttytype_sbbuf); 565 1.4 jtk DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2, 566 1.4 jtk sizeof ttytype_sbbuf - 2);); 567 1.1 cgd } 568 1.1 cgd if (his_state_is_will(TELOPT_TSPEED)) { 569 1.1 cgd while (sequenceIs(tspeedsubopt, baseline)) 570 1.1 cgd ttloop(); 571 1.1 cgd } 572 1.1 cgd if (his_state_is_will(TELOPT_XDISPLOC)) { 573 1.1 cgd while (sequenceIs(xdisplocsubopt, baseline)) 574 1.1 cgd ttloop(); 575 1.1 cgd } 576 1.3 cgd if (his_state_is_will(TELOPT_NEW_ENVIRON)) { 577 1.1 cgd while (sequenceIs(environsubopt, baseline)) 578 1.1 cgd ttloop(); 579 1.1 cgd } 580 1.3 cgd if (his_state_is_will(TELOPT_OLD_ENVIRON)) { 581 1.3 cgd while (sequenceIs(oenvironsubopt, baseline)) 582 1.3 cgd ttloop(); 583 1.3 cgd } 584 1.1 cgd if (his_state_is_will(TELOPT_TTYPE)) { 585 1.1 cgd char first[256], last[256]; 586 1.1 cgd 587 1.1 cgd while (sequenceIs(ttypesubopt, baseline)) 588 1.1 cgd ttloop(); 589 1.1 cgd 590 1.1 cgd /* 591 1.1 cgd * If the other side has already disabled the option, then 592 1.1 cgd * we have to just go with what we (might) have already gotten. 593 1.1 cgd */ 594 1.1 cgd if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) { 595 1.37 itojun (void) strlcpy(first, terminaltype, sizeof(first)); 596 1.1 cgd for(;;) { 597 1.1 cgd /* 598 1.1 cgd * Save the unknown name, and request the next name. 599 1.1 cgd */ 600 1.37 itojun (void) strlcpy(last, terminaltype, sizeof(last)); 601 1.1 cgd _gettermname(); 602 1.1 cgd if (terminaltypeok(terminaltype)) 603 1.1 cgd break; 604 1.1 cgd if ((strncmp(last, terminaltype, sizeof(last)) == 0) || 605 1.1 cgd his_state_is_wont(TELOPT_TTYPE)) { 606 1.1 cgd /* 607 1.1 cgd * We've hit the end. If this is the same as 608 1.1 cgd * the first name, just go with it. 609 1.1 cgd */ 610 1.1 cgd if (strncmp(first, terminaltype, sizeof(first)) == 0) 611 1.1 cgd break; 612 1.1 cgd /* 613 1.1 cgd * Get the terminal name one more time, so that 614 1.1 cgd * RFC1091 compliant telnets will cycle back to 615 1.1 cgd * the start of the list. 616 1.1 cgd */ 617 1.1 cgd _gettermname(); 618 1.21 thorpej if (strncmp(first, terminaltype, sizeof(first)) != 0) { 619 1.48 lha (void) strlcpy(terminaltype, first, sizeof(terminaltype)); 620 1.21 thorpej } 621 1.1 cgd break; 622 1.1 cgd } 623 1.1 cgd } 624 1.1 cgd } 625 1.1 cgd } 626 1.1 cgd return(retval); 627 1.1 cgd } /* end of getterminaltype */ 628 1.1 cgd 629 1.39 itojun void 630 1.46 perry _gettermname(void) 631 1.1 cgd { 632 1.1 cgd /* 633 1.1 cgd * If the client turned off the option, 634 1.1 cgd * we can't send another request, so we 635 1.1 cgd * just return. 636 1.1 cgd */ 637 1.1 cgd if (his_state_is_wont(TELOPT_TTYPE)) 638 1.1 cgd return; 639 1.1 cgd settimer(baseline); 640 1.27 wiz output_datalen((const char *)ttytype_sbbuf, sizeof ttytype_sbbuf); 641 1.4 jtk DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2, 642 1.4 jtk sizeof ttytype_sbbuf - 2);); 643 1.1 cgd while (sequenceIs(ttypesubopt, baseline)) 644 1.1 cgd ttloop(); 645 1.1 cgd } 646 1.1 cgd 647 1.39 itojun int 648 1.46 perry terminaltypeok(char *s) 649 1.1 cgd { 650 1.1 cgd char buf[1024]; 651 1.1 cgd 652 1.1 cgd /* 653 1.1 cgd * tgetent() will return 1 if the type is known, and 654 1.1 cgd * 0 if it is not known. If it returns -1, it couldn't 655 1.1 cgd * open the database. But if we can't open the database, 656 1.1 cgd * it won't help to say we failed, because we won't be 657 1.1 cgd * able to verify anything else. So, we treat -1 like 1. 658 1.1 cgd */ 659 1.1 cgd if (tgetent(buf, s) == 0) 660 1.1 cgd return(0); 661 1.1 cgd return(1); 662 1.1 cgd } 663 1.1 cgd 664 1.1 cgd char *hostname; 665 1.13 mrg char host_name[MAXHOSTNAMELEN + 1]; 666 1.13 mrg char remote_host_name[MAXHOSTNAMELEN + 1]; 667 1.1 cgd 668 1.54 joerg static void telnet(int, int) __dead; 669 1.1 cgd 670 1.1 cgd /* 671 1.1 cgd * Get a pty, scan input lines. 672 1.1 cgd */ 673 1.54 joerg static void 674 1.46 perry doit(struct sockaddr *who) 675 1.1 cgd { 676 1.9 mrg char *host; 677 1.16 itojun int error; 678 1.1 cgd int level; 679 1.3 cgd int ptynum; 680 1.36 christos int flags; 681 1.1 cgd char user_name[256]; 682 1.1 cgd 683 1.1 cgd /* 684 1.58 dholland * Initialize the slc mapping table. 685 1.58 dholland */ 686 1.58 dholland get_slc_defaults(); 687 1.58 dholland 688 1.58 dholland /* 689 1.1 cgd * Find an available pty to use. 690 1.1 cgd */ 691 1.3 cgd pty = getpty(&ptynum); 692 1.1 cgd if (pty < 0) 693 1.1 cgd fatal(net, "All network ports in use"); 694 1.3 cgd 695 1.36 christos flags = registerd_host_only ? NI_NAMEREQD : 0; 696 1.36 christos 697 1.1 cgd /* get name of connected client */ 698 1.32 itojun error = getnameinfo(who, who->sa_len, remote_host_name, 699 1.36 christos sizeof(remote_host_name), NULL, 0, flags); 700 1.32 itojun 701 1.16 itojun if (error) { 702 1.3 cgd fatal(net, "Couldn't resolve your address into a host name.\r\n\ 703 1.4 jtk Please contact your net administrator"); 704 1.9 mrg #ifdef __GNUC__ 705 1.9 mrg host = NULL; /* XXX gcc */ 706 1.9 mrg #endif 707 1.3 cgd } 708 1.16 itojun 709 1.1 cgd remote_host_name[sizeof(remote_host_name)-1] = 0; 710 1.1 cgd host = remote_host_name; 711 1.1 cgd 712 1.39 itojun (void)gethostname(host_name, sizeof(host_name)); 713 1.13 mrg host_name[sizeof(host_name) - 1] = '\0'; 714 1.1 cgd hostname = host_name; 715 1.1 cgd 716 1.21 thorpej #if defined(AUTHENTICATION) || defined(ENCRYPTION) 717 1.1 cgd auth_encrypt_init(hostname, host, "TELNETD", 1); 718 1.1 cgd #endif 719 1.1 cgd 720 1.1 cgd init_env(); 721 1.1 cgd /* 722 1.1 cgd * get terminal type. 723 1.1 cgd */ 724 1.1 cgd *user_name = 0; 725 1.41 itojun level = getterminaltype(user_name, sizeof(user_name)); 726 1.48 lha setenv("TERM", terminaltype[0] ? terminaltype : "network", 1); 727 1.1 cgd 728 1.1 cgd /* 729 1.1 cgd * Start up the login process on the slave side of the terminal 730 1.1 cgd */ 731 1.1 cgd startslave(host, level, user_name); 732 1.1 cgd 733 1.1 cgd telnet(net, pty); /* begin server processing */ 734 1.1 cgd /*NOTREACHED*/ 735 1.1 cgd } /* end of doit */ 736 1.1 cgd 737 1.1 cgd 738 1.1 cgd /* 739 1.1 cgd * Main loop. Select from pty and network, and 740 1.1 cgd * hand data to telnet receiver finite state machine. 741 1.1 cgd */ 742 1.54 joerg static void 743 1.46 perry telnet(int f, int p) 744 1.1 cgd { 745 1.1 cgd int on = 1; 746 1.1 cgd #define TABBUFSIZ 512 747 1.1 cgd char defent[TABBUFSIZ]; 748 1.1 cgd char defstrs[TABBUFSIZ]; 749 1.1 cgd #undef TABBUFSIZ 750 1.53 christos char *HE, *HN, *IF, *ptyibuf2ptr; 751 1.53 christos const char *IM; 752 1.35 mycroft struct pollfd set[2]; 753 1.1 cgd 754 1.1 cgd /* 755 1.57 andvar * Do some tests where it is desirable to wait for a response. 756 1.1 cgd * Rather than doing them slowly, one at a time, do them all 757 1.1 cgd * at once. 758 1.1 cgd */ 759 1.1 cgd if (my_state_is_wont(TELOPT_SGA)) 760 1.1 cgd send_will(TELOPT_SGA, 1); 761 1.1 cgd /* 762 1.1 cgd * Is the client side a 4.2 (NOT 4.3) system? We need to know this 763 1.1 cgd * because 4.2 clients are unable to deal with TCP urgent data. 764 1.1 cgd * 765 1.1 cgd * To find out, we send out a "DO ECHO". If the remote system 766 1.1 cgd * answers "WILL ECHO" it is probably a 4.2 client, and we note 767 1.1 cgd * that fact ("WILL ECHO" ==> that the client will echo what 768 1.1 cgd * WE, the server, sends it; it does NOT mean that the client will 769 1.1 cgd * echo the terminal input). 770 1.1 cgd */ 771 1.1 cgd send_do(TELOPT_ECHO, 1); 772 1.1 cgd 773 1.1 cgd #ifdef LINEMODE 774 1.1 cgd if (his_state_is_wont(TELOPT_LINEMODE)) { 775 1.1 cgd /* Query the peer for linemode support by trying to negotiate 776 1.1 cgd * the linemode option. 777 1.1 cgd */ 778 1.1 cgd linemode = 0; 779 1.1 cgd editmode = 0; 780 1.1 cgd send_do(TELOPT_LINEMODE, 1); /* send do linemode */ 781 1.1 cgd } 782 1.1 cgd #endif /* LINEMODE */ 783 1.1 cgd 784 1.1 cgd /* 785 1.1 cgd * Send along a couple of other options that we wish to negotiate. 786 1.1 cgd */ 787 1.1 cgd send_do(TELOPT_NAWS, 1); 788 1.1 cgd send_will(TELOPT_STATUS, 1); 789 1.3 cgd flowmode = 1; /* default flow control state */ 790 1.3 cgd restartany = -1; /* uninitialized... */ 791 1.1 cgd send_do(TELOPT_LFLOW, 1); 792 1.1 cgd 793 1.1 cgd /* 794 1.1 cgd * Spin, waiting for a response from the DO ECHO. However, 795 1.1 cgd * some REALLY DUMB telnets out there might not respond 796 1.1 cgd * to the DO ECHO. So, we spin looking for NAWS, (most dumb 797 1.1 cgd * telnets so far seem to respond with WONT for a DO that 798 1.1 cgd * they don't understand...) because by the time we get the 799 1.1 cgd * response, it will already have processed the DO ECHO. 800 1.1 cgd * Kludge upon kludge. 801 1.1 cgd */ 802 1.1 cgd while (his_will_wont_is_changing(TELOPT_NAWS)) 803 1.1 cgd ttloop(); 804 1.1 cgd 805 1.1 cgd /* 806 1.1 cgd * But... 807 1.1 cgd * The client might have sent a WILL NAWS as part of its 808 1.1 cgd * startup code; if so, we'll be here before we get the 809 1.1 cgd * response to the DO ECHO. We'll make the assumption 810 1.1 cgd * that any implementation that understands about NAWS 811 1.1 cgd * is a modern enough implementation that it will respond 812 1.1 cgd * to our DO ECHO request; hence we'll do another spin 813 1.1 cgd * waiting for the ECHO option to settle down, which is 814 1.1 cgd * what we wanted to do in the first place... 815 1.1 cgd */ 816 1.1 cgd if (his_want_state_is_will(TELOPT_ECHO) && 817 1.1 cgd his_state_is_will(TELOPT_NAWS)) { 818 1.1 cgd while (his_will_wont_is_changing(TELOPT_ECHO)) 819 1.1 cgd ttloop(); 820 1.1 cgd } 821 1.1 cgd /* 822 1.1 cgd * On the off chance that the telnet client is broken and does not 823 1.1 cgd * respond to the DO ECHO we sent, (after all, we did send the 824 1.1 cgd * DO NAWS negotiation after the DO ECHO, and we won't get here 825 1.1 cgd * until a response to the DO NAWS comes back) simulate the 826 1.1 cgd * receipt of a will echo. This will also send a WONT ECHO 827 1.1 cgd * to the client, since we assume that the client failed to 828 1.1 cgd * respond because it believes that it is already in DO ECHO 829 1.1 cgd * mode, which we do not want. 830 1.1 cgd */ 831 1.1 cgd if (his_want_state_is_will(TELOPT_ECHO)) { 832 1.1 cgd DIAG(TD_OPTIONS, 833 1.26 itojun {output_data("td: simulating recv\r\n");}); 834 1.1 cgd willoption(TELOPT_ECHO); 835 1.1 cgd } 836 1.1 cgd 837 1.1 cgd /* 838 1.1 cgd * Finally, to clean things up, we turn on our echo. This 839 1.1 cgd * will break stupid 4.2 telnets out of local terminal echo. 840 1.1 cgd */ 841 1.1 cgd 842 1.1 cgd if (my_state_is_wont(TELOPT_ECHO)) 843 1.1 cgd send_will(TELOPT_ECHO, 1); 844 1.1 cgd 845 1.1 cgd /* 846 1.1 cgd * Turn on packet mode 847 1.1 cgd */ 848 1.1 cgd (void) ioctl(p, TIOCPKT, (char *)&on); 849 1.3 cgd 850 1.1 cgd #if defined(LINEMODE) && defined(KLUDGELINEMODE) 851 1.1 cgd /* 852 1.1 cgd * Continuing line mode support. If client does not support 853 1.1 cgd * real linemode, attempt to negotiate kludge linemode by sending 854 1.1 cgd * the do timing mark sequence. 855 1.1 cgd */ 856 1.1 cgd if (lmodetype < REAL_LINEMODE) 857 1.1 cgd send_do(TELOPT_TM, 1); 858 1.1 cgd #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 859 1.1 cgd 860 1.1 cgd /* 861 1.1 cgd * Call telrcv() once to pick up anything received during 862 1.1 cgd * terminal type negotiation, 4.2/4.3 determination, and 863 1.1 cgd * linemode negotiation. 864 1.1 cgd */ 865 1.1 cgd telrcv(); 866 1.1 cgd 867 1.1 cgd (void) ioctl(f, FIONBIO, (char *)&on); 868 1.1 cgd (void) ioctl(p, FIONBIO, (char *)&on); 869 1.1 cgd 870 1.39 itojun (void) setsockopt(f, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof on); 871 1.1 cgd 872 1.1 cgd (void) signal(SIGTSTP, SIG_IGN); 873 1.1 cgd /* 874 1.1 cgd * Ignoring SIGTTOU keeps the kernel from blocking us 875 1.1 cgd * in ttioct() in /sys/tty.c. 876 1.1 cgd */ 877 1.1 cgd (void) signal(SIGTTOU, SIG_IGN); 878 1.1 cgd 879 1.1 cgd (void) signal(SIGCHLD, cleanup); 880 1.1 cgd 881 1.1 cgd 882 1.1 cgd { 883 1.46 perry int t; 884 1.1 cgd t = open(_PATH_TTY, O_RDWR); 885 1.1 cgd if (t >= 0) { 886 1.1 cgd (void) ioctl(t, TIOCNOTTY, (char *)0); 887 1.1 cgd (void) close(t); 888 1.1 cgd } 889 1.1 cgd } 890 1.1 cgd 891 1.1 cgd 892 1.1 cgd /* 893 1.1 cgd * Show banner that getty never gave. 894 1.1 cgd * 895 1.1 cgd * We put the banner in the pty input buffer. This way, it 896 1.1 cgd * gets carriage return null processing, etc., just like all 897 1.1 cgd * other pty --> client data. 898 1.1 cgd */ 899 1.1 cgd 900 1.6 tls if (getent(defent, gettyname) == 1) { 901 1.1 cgd char *cp=defstrs; 902 1.1 cgd 903 1.1 cgd HE = getstr("he", &cp); 904 1.1 cgd HN = getstr("hn", &cp); 905 1.1 cgd IM = getstr("im", &cp); 906 1.20 ad IF = getstr("if", &cp); 907 1.1 cgd if (HN && *HN) 908 1.23 christos (void)strlcpy(host_name, HN, sizeof(host_name)); 909 1.1 cgd if (IM == 0) 910 1.1 cgd IM = ""; 911 1.1 cgd } else { 912 1.1 cgd IM = DEFAULT_IM; 913 1.1 cgd HE = 0; 914 1.47 lukem IF = NULL; 915 1.1 cgd } 916 1.1 cgd edithost(HE, host_name); 917 1.20 ad ptyibuf2ptr = ptyibuf2; 918 1.20 ad if (hostinfo) { 919 1.20 ad if (IF) { 920 1.20 ad char buf[_POSIX2_LINE_MAX]; 921 1.20 ad FILE *fd; 922 1.46 perry 923 1.20 ad if ((fd = fopen(IF, "r")) != NULL) { 924 1.20 ad while (fgets(buf, sizeof(buf) - 1, fd) != NULL) 925 1.20 ad ptyibuf2ptr = putf(buf, ptyibuf2ptr); 926 1.20 ad fclose(fd); 927 1.20 ad } 928 1.20 ad } 929 1.20 ad if (*IM) 930 1.20 ad ptyibuf2ptr = putf(IM, ptyibuf2ptr); 931 1.20 ad } 932 1.1 cgd 933 1.1 cgd if (pcc) 934 1.20 ad strncpy(ptyibuf2ptr, ptyip, pcc+1); 935 1.1 cgd ptyip = ptyibuf2; 936 1.1 cgd pcc = strlen(ptyip); 937 1.1 cgd #ifdef LINEMODE 938 1.1 cgd /* 939 1.1 cgd * Last check to make sure all our states are correct. 940 1.1 cgd */ 941 1.1 cgd init_termbuf(); 942 1.1 cgd localstat(); 943 1.1 cgd #endif /* LINEMODE */ 944 1.1 cgd 945 1.1 cgd DIAG(TD_REPORT, 946 1.26 itojun {output_data("td: Entering processing loop\r\n");}); 947 1.1 cgd 948 1.1 cgd 949 1.35 mycroft set[0].fd = f; 950 1.35 mycroft set[1].fd = p; 951 1.1 cgd for (;;) { 952 1.46 perry int c; 953 1.1 cgd 954 1.1 cgd if (ncc < 0 && pcc < 0) 955 1.1 cgd break; 956 1.1 cgd 957 1.1 cgd /* 958 1.1 cgd * Never look for input if there's still 959 1.1 cgd * stuff in the corresponding output buffer 960 1.1 cgd */ 961 1.34 mycroft set[0].events = 0; 962 1.34 mycroft set[1].events = 0; 963 1.34 mycroft if (nfrontp - nbackp || pcc > 0) 964 1.34 mycroft set[0].events |= POLLOUT; 965 1.34 mycroft else 966 1.34 mycroft set[1].events |= POLLIN; 967 1.34 mycroft if (pfrontp - pbackp || ncc > 0) 968 1.34 mycroft set[1].events |= POLLOUT; 969 1.34 mycroft else 970 1.34 mycroft set[0].events |= POLLIN; 971 1.34 mycroft if (!SYNCHing) 972 1.34 mycroft set[0].events |= POLLPRI; 973 1.34 mycroft 974 1.34 mycroft if ((c = poll(set, 2, INFTIM)) < 1) { 975 1.1 cgd if (c == -1) { 976 1.1 cgd if (errno == EINTR) { 977 1.1 cgd continue; 978 1.1 cgd } 979 1.1 cgd } 980 1.1 cgd sleep(5); 981 1.1 cgd continue; 982 1.1 cgd } 983 1.1 cgd 984 1.1 cgd /* 985 1.1 cgd * Any urgent data? 986 1.1 cgd */ 987 1.34 mycroft if (set[0].revents & POLLPRI) { 988 1.1 cgd SYNCHing = 1; 989 1.1 cgd } 990 1.1 cgd 991 1.1 cgd /* 992 1.1 cgd * Something to read from the network... 993 1.1 cgd */ 994 1.45 christos if (set[0].revents & POLLIN) { 995 1.34 mycroft ncc = read(f, netibuf, sizeof (netibuf)); 996 1.1 cgd if (ncc < 0 && errno == EWOULDBLOCK) 997 1.1 cgd ncc = 0; 998 1.1 cgd else { 999 1.1 cgd if (ncc <= 0) { 1000 1.1 cgd break; 1001 1.1 cgd } 1002 1.1 cgd netip = netibuf; 1003 1.1 cgd } 1004 1.1 cgd DIAG((TD_REPORT | TD_NETDATA), 1005 1.26 itojun {output_data("td: netread %d chars\r\n", ncc);}); 1006 1.1 cgd DIAG(TD_NETDATA, printdata("nd", netip, ncc)); 1007 1.1 cgd } 1008 1.1 cgd 1009 1.1 cgd /* 1010 1.1 cgd * Something to read from the pty... 1011 1.1 cgd */ 1012 1.34 mycroft if (set[1].revents & POLLIN) { 1013 1.1 cgd pcc = read(p, ptyibuf, BUFSIZ); 1014 1.1 cgd /* 1015 1.1 cgd * On some systems, if we try to read something 1016 1.1 cgd * off the master side before the slave side is 1017 1.1 cgd * opened, we get EIO. 1018 1.1 cgd */ 1019 1.3 cgd if (pcc < 0 && (errno == EWOULDBLOCK || 1020 1.3 cgd errno == EAGAIN || 1021 1.3 cgd errno == EIO)) { 1022 1.1 cgd pcc = 0; 1023 1.1 cgd } else { 1024 1.1 cgd if (pcc <= 0) 1025 1.1 cgd break; 1026 1.1 cgd #ifdef LINEMODE 1027 1.1 cgd /* 1028 1.1 cgd * If ioctl from pty, pass it through net 1029 1.1 cgd */ 1030 1.1 cgd if (ptyibuf[0] & TIOCPKT_IOCTL) { 1031 1.1 cgd copy_termbuf(ptyibuf+1, pcc-1); 1032 1.1 cgd localstat(); 1033 1.1 cgd pcc = 1; 1034 1.1 cgd } 1035 1.1 cgd #endif /* LINEMODE */ 1036 1.1 cgd if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) { 1037 1.1 cgd netclear(); /* clear buffer back */ 1038 1.1 cgd /* 1039 1.1 cgd * There are client telnets on some 1040 1.1 cgd * operating systems get screwed up 1041 1.1 cgd * royally if we send them urgent 1042 1.1 cgd * mode data. 1043 1.1 cgd */ 1044 1.26 itojun output_data("%c%c", IAC, DM); 1045 1.26 itojun neturg = nfrontp - 1; /* off by one XXX */ 1046 1.4 jtk DIAG(TD_OPTIONS, 1047 1.4 jtk printoption("td: send IAC", DM)); 1048 1.1 cgd } 1049 1.1 cgd if (his_state_is_will(TELOPT_LFLOW) && 1050 1.1 cgd (ptyibuf[0] & 1051 1.1 cgd (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) { 1052 1.3 cgd int newflow = 1053 1.3 cgd ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0; 1054 1.3 cgd if (newflow != flowmode) { 1055 1.3 cgd flowmode = newflow; 1056 1.26 itojun (void) output_data( 1057 1.3 cgd "%c%c%c%c%c%c", 1058 1.3 cgd IAC, SB, TELOPT_LFLOW, 1059 1.3 cgd flowmode ? LFLOW_ON 1060 1.3 cgd : LFLOW_OFF, 1061 1.3 cgd IAC, SE); 1062 1.4 jtk DIAG(TD_OPTIONS, printsub('>', 1063 1.26 itojun (unsigned char *)nfrontp - 4, 1064 1.4 jtk 4);); 1065 1.3 cgd } 1066 1.1 cgd } 1067 1.1 cgd pcc--; 1068 1.1 cgd ptyip = ptyibuf+1; 1069 1.1 cgd } 1070 1.1 cgd } 1071 1.1 cgd 1072 1.1 cgd while (pcc > 0) { 1073 1.1 cgd if ((&netobuf[BUFSIZ] - nfrontp) < 2) 1074 1.1 cgd break; 1075 1.1 cgd c = *ptyip++ & 0377, pcc--; 1076 1.1 cgd if (c == IAC) 1077 1.26 itojun output_data("%c", c); 1078 1.26 itojun output_data("%c", c); 1079 1.1 cgd if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) { 1080 1.1 cgd if (pcc > 0 && ((*ptyip & 0377) == '\n')) { 1081 1.26 itojun output_data("%c", *ptyip++ & 0377); 1082 1.1 cgd pcc--; 1083 1.1 cgd } else 1084 1.26 itojun output_datalen("\0", 1); 1085 1.1 cgd } 1086 1.1 cgd } 1087 1.1 cgd 1088 1.45 christos if ((set[0].revents & POLLOUT) && (nfrontp - nbackp) > 0) 1089 1.1 cgd netflush(); 1090 1.1 cgd if (ncc > 0) 1091 1.1 cgd telrcv(); 1092 1.45 christos if ((set[1].revents & POLLOUT) && (pfrontp - pbackp) > 0) 1093 1.1 cgd ptyflush(); 1094 1.1 cgd } 1095 1.1 cgd cleanup(0); 1096 1.1 cgd } /* end of telnet */ 1097 1.4 jtk 1098 1.1 cgd /* 1099 1.1 cgd * Send interrupt to process on other side of pty. 1100 1.1 cgd * If it is in raw mode, just write NULL; 1101 1.1 cgd * otherwise, write intr char. 1102 1.1 cgd */ 1103 1.39 itojun void 1104 1.46 perry interrupt(void) 1105 1.1 cgd { 1106 1.1 cgd ptyflush(); /* half-hearted */ 1107 1.1 cgd 1108 1.39 itojun (void) ioctl(pty, TIOCSIG, (char *)SIGINT); 1109 1.1 cgd } 1110 1.1 cgd 1111 1.1 cgd /* 1112 1.1 cgd * Send quit to process on other side of pty. 1113 1.1 cgd * If it is in raw mode, just write NULL; 1114 1.1 cgd * otherwise, write quit char. 1115 1.1 cgd */ 1116 1.39 itojun void 1117 1.46 perry sendbrk(void) 1118 1.1 cgd { 1119 1.1 cgd ptyflush(); /* half-hearted */ 1120 1.39 itojun (void) ioctl(pty, TIOCSIG, (char *)SIGQUIT); 1121 1.1 cgd } 1122 1.1 cgd 1123 1.39 itojun void 1124 1.46 perry sendsusp(void) 1125 1.1 cgd { 1126 1.1 cgd ptyflush(); /* half-hearted */ 1127 1.39 itojun (void) ioctl(pty, TIOCSIG, (char *)SIGTSTP); 1128 1.1 cgd } 1129 1.1 cgd 1130 1.1 cgd /* 1131 1.1 cgd * When we get an AYT, if ^T is enabled, use that. Otherwise, 1132 1.1 cgd * just send back "[Yes]". 1133 1.1 cgd */ 1134 1.39 itojun void 1135 1.46 perry recv_ayt(void) 1136 1.1 cgd { 1137 1.1 cgd if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) { 1138 1.39 itojun (void) ioctl(pty, TIOCSIG, (char *)SIGINFO); 1139 1.1 cgd return; 1140 1.1 cgd } 1141 1.26 itojun (void) output_data("\r\n[Yes]\r\n"); 1142 1.1 cgd } 1143 1.1 cgd 1144 1.39 itojun void 1145 1.46 perry doeof(void) 1146 1.1 cgd { 1147 1.1 cgd init_termbuf(); 1148 1.1 cgd 1149 1.39 itojun #if defined(LINEMODE) && (VEOF == VMIN) 1150 1.1 cgd if (!tty_isediting()) { 1151 1.1 cgd extern char oldeofc; 1152 1.1 cgd *pfrontp++ = oldeofc; 1153 1.1 cgd return; 1154 1.1 cgd } 1155 1.1 cgd #endif 1156 1.1 cgd *pfrontp++ = slctab[SLC_EOF].sptr ? 1157 1.1 cgd (unsigned char)*slctab[SLC_EOF].sptr : '\004'; 1158 1.1 cgd } 1159