Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/networking/telnetd.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/networking/telnetd.c
r821 r1770 22 22 */ 23 23 24 /*#define DEBUG 1 */ 25 #undef DEBUG 26 27 #include <sys/socket.h> 28 #include <sys/wait.h> 29 #include <sys/ioctl.h> 30 #include <string.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <errno.h> 34 #include <netinet/in.h> 35 #include <arpa/inet.h> 36 #include <fcntl.h> 37 #include <stdio.h> 38 #include <signal.h> 39 #include <termios.h> 40 #ifdef DEBUG 24 #define DEBUG 0 25 26 #include "libbb.h" 27 28 #if DEBUG 41 29 #define TELCMDS 42 30 #define TELOPTS 43 31 #endif 44 32 #include <arpa/telnet.h> 45 #include <ctype.h>46 33 #include <sys/syslog.h> 47 34 48 #include "busybox.h" 49 50 #define BUFSIZE 4000 51 52 #ifdef CONFIG_FEATURE_IPV6 53 #define SOCKET_TYPE AF_INET6 54 typedef struct sockaddr_in6 sockaddr_type; 55 #else 56 #define SOCKET_TYPE AF_INET 57 typedef struct sockaddr_in sockaddr_type; 58 #endif 59 60 61 #ifdef CONFIG_LOGIN 35 36 #if ENABLE_LOGIN 62 37 static const char *loginpath = "/bin/login"; 63 38 #else 64 static const char *loginpath; 65 #endif 39 static const char *loginpath = DEFAULT_SHELL; 40 #endif 41 66 42 static const char *issuefile = "/etc/issue.net"; 67 43 68 /* shell name and arguments */69 70 static const char *argv_init[] = {NULL, NULL};71 72 44 /* structure that describes a session */ 73 45 74 46 struct tsession { 75 #ifdef CONFIG_FEATURE_TELNETD_INETD 47 struct tsession *next; 76 48 int sockfd_read, sockfd_write, ptyfd; 77 #else /* CONFIG_FEATURE_TELNETD_INETD */78 struct tsession *next;79 int sockfd, ptyfd;80 #endif /* CONFIG_FEATURE_TELNETD_INETD */81 49 int shell_pid; 82 50 /* two circular buffers */ … … 86 54 }; 87 55 56 /* Two buffers are directly after tsession in malloced memory. 57 * Make whole thing fit in 4k */ 58 enum { BUFSIZE = (4*1024 - sizeof(struct tsession)) / 2 }; 59 88 60 /* 89 90 61 This is how the buffers are used. The arrows indicate the movement 91 62 of data. … … 100 71 101 72 Each session has got two buffers. 102 103 73 */ 104 74 … … 109 79 110 80 /* 111 112 81 Remove all IAC's from the buffer pointed to by bf (received IACs are ignored 113 82 and must be removed so as to not be interpreted by the terminal). Make an … … 127 96 128 97 CR-LF ->'s CR mapping is also done here, for convenience 129 130 */ 98 */ 131 99 static char * 132 remove_iacs(struct tsession *ts, int *pnum_totty) { 100 remove_iacs(struct tsession *ts, int *pnum_totty) 101 { 133 102 unsigned char *ptr0 = (unsigned char *)ts->buf1 + ts->wridx1; 134 103 unsigned char *ptr = ptr0; … … 148 117 if (c == '\r' && (*ptr == '\n' || *ptr == 0) && ptr < end) 149 118 ptr++; 150 } 151 else { 119 } else { 152 120 /* 153 121 * TELOPT_NAWS support! … … 169 137 ws.ws_col = (ptr[3] << 8) | ptr[4]; 170 138 ws.ws_row = (ptr[5] << 8) | ptr[6]; 171 (void)ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);139 ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); 172 140 ptr += 9; 173 } 174 else { 141 } else { 175 142 /* skip 3-byte IAC non-SB cmd */ 176 #if defDEBUG143 #if DEBUG 177 144 fprintf(stderr, "Ignoring IAC %s,%s\n", 178 TELCMD( *(ptr+1)), TELOPT(*(ptr+2)));145 TELCMD(ptr[1]), TELOPT(ptr[2])); 179 146 #endif 180 147 ptr += 3; … … 198 165 199 166 static int 200 getpty(char *line )167 getpty(char *line, int size) 201 168 { 202 169 int p; 203 #if def CONFIG_FEATURE_DEVPTS204 p = open("/dev/ptmx", 2);170 #if ENABLE_FEATURE_DEVPTS 171 p = open("/dev/ptmx", O_RDWR); 205 172 if (p > 0) { 173 const char *name; 206 174 grantpt(p); 207 175 unlockpt(p); 208 strcpy(line, ptsname(p)); 209 return(p); 176 name = ptsname(p); 177 if (!name) { 178 bb_perror_msg("ptsname error (is /dev/pts mounted?)"); 179 return -1; 180 } 181 safe_strncpy(line, name, size); 182 return p; 210 183 } 211 184 #else … … 224 197 for (j = 0; j < 16; j++) { 225 198 line[9] = j < 10 ? j + '0' : j - 10 + 'a'; 226 #ifdef DEBUG 227 fprintf(stderr, "Trying to open device: %s\n", line);228 #endif 229 if ( (p = open(line, O_RDWR | O_NOCTTY))>= 0) {199 if (DEBUG) 200 fprintf(stderr, "Trying to open device: %s\n", line); 201 p = open(line, O_RDWR | O_NOCTTY); 202 if (p >= 0) { 230 203 line[5] = 't'; 231 204 return p; … … 233 206 } 234 207 } 235 #endif /* CONFIG_FEATURE_DEVPTS */208 #endif /* FEATURE_DEVPTS */ 236 209 return -1; 237 210 } … … 241 214 send_iac(struct tsession *ts, unsigned char command, int option) 242 215 { 243 /* We rely on that there is space in the buffer for now. 216 /* We rely on that there is space in the buffer for now. */ 244 217 char *b = ts->buf2 + ts->rdidx2; 245 218 *b++ = IAC; … … 252 225 253 226 static struct tsession * 254 #ifdef CONFIG_FEATURE_TELNETD_INETD 255 make_new_session(void) 256 #else /* CONFIG_FEATURE_TELNETD_INETD */ 257 make_new_session(int sockfd) 258 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 259 { 227 make_new_session( 228 USE_FEATURE_TELNETD_STANDALONE(int sock_r, int sock_w) 229 SKIP_FEATURE_TELNETD_STANDALONE(void) 230 ) { 231 const char *login_argv[2]; 260 232 struct termios termbuf; 261 int pty, pid;233 int fd, pid; 262 234 char tty_name[32]; 263 235 struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2); … … 266 238 ts->buf2 = ts->buf1 + BUFSIZE; 267 239 268 #ifdef CONFIG_FEATURE_TELNETD_INETD 240 /* Got a new connection, set up a tty. */ 241 fd = getpty(tty_name, 32); 242 if (fd < 0) { 243 bb_error_msg("all terminals in use"); 244 return NULL; 245 } 246 if (fd > maxfd) maxfd = fd; 247 ndelay_on(ts->ptyfd = fd); 248 #if ENABLE_FEATURE_TELNETD_STANDALONE 249 if (sock_w > maxfd) maxfd = sock_w; 250 if (sock_r > maxfd) maxfd = sock_r; 251 ndelay_on(ts->sockfd_write = sock_w); 252 ndelay_on(ts->sockfd_read = sock_r); 253 #else 269 254 ts->sockfd_write = 1; 270 #else /* CONFIG_FEATURE_TELNETD_INETD */ 271 ts->sockfd = sockfd; 272 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 273 274 /* Got a new connection, set up a tty and spawn a shell. */ 275 276 pty = getpty(tty_name); 277 278 if (pty < 0) { 279 syslog(LOG_ERR, "All terminals in use!"); 280 return 0; 281 } 282 283 if (pty > maxfd) 284 maxfd = pty; 285 286 ts->ptyfd = pty; 287 255 /* xzalloc: ts->sockfd_read = 0; */ 256 ndelay_on(0); 257 ndelay_on(1); 258 #endif 288 259 /* Make the telnet client understand we will echo characters so it 289 260 * should not do it locally. We don't tell the client to run linemode, 290 261 * because we want to handle line editing and tab completion and other 291 * stuff that requires char-by-char support. 292 */ 293 262 * stuff that requires char-by-char support. */ 294 263 send_iac(ts, DO, TELOPT_ECHO); 295 264 send_iac(ts, DO, TELOPT_NAWS); … … 298 267 send_iac(ts, WILL, TELOPT_SGA); 299 268 300 if ((pid = fork()) < 0) {301 syslog(LOG_ERR, "Could not fork");302 }303 if (pid == 0) {304 /* In child, open the child's side of the tty. */305 int i;306 307 for(i = 0; i <= maxfd; i++)308 close(i);309 /* make new process group */310 setsid();311 312 if (open(tty_name, O_RDWR /*| O_NOCTTY*/) < 0) { 313 syslog(LOG_ERR, "Could not open tty");314 exit(1); 315 }316 dup(0);317 dup(0); 318 319 tcsetpgrp(0, getpid());320 321 /* The pseudo-terminal allocated to the client is configured to operate in322 * cooked mode, and with XTABS CRMOD enabled (see tty(4)).323 */324 325 tcgetattr(0, &termbuf);326 termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */327 termbuf.c_oflag |= ONLCR|XTABS; 328 termbuf.c_iflag |= ICRNL;329 termbuf.c_iflag &= ~IXOFF;330 /*termbuf.c_lflag &= ~ICANON;*/331 tcsetattr(0, TCSANOW, &termbuf);332 333 print_login_issue(issuefile, NULL);334 335 /* exec shell, with correct argv and env*/336 execv(loginpath, (char *const *)argv_init);337 338 /* NOT REACHED */339 syslog(LOG_ERR, "execv error"); 340 exit(1);341 }342 343 ts->shell_pid = pid;344 345 return ts;269 pid = fork(); 270 if (pid < 0) { 271 free(ts); 272 close(fd); 273 bb_perror_msg("fork"); 274 return NULL; 275 } 276 if (pid > 0) { 277 /* parent */ 278 ts->shell_pid = pid; 279 return ts; 280 } 281 282 /* child */ 283 284 /* make new session and process group */ 285 setsid(); 286 287 /* open the child's side of the tty. */ 288 /* NB: setsid() disconnects from any previous ctty's. Therefore 289 * we must open child's side of the tty AFTER setsid! */ 290 fd = xopen(tty_name, O_RDWR); /* becomes our ctty */ 291 dup2(fd, 0); 292 dup2(fd, 1); 293 dup2(fd, 2); 294 while (fd > 2) close(fd--); 295 tcsetpgrp(0, getpid()); /* switch this tty's process group to us */ 296 297 /* The pseudo-terminal allocated to the client is configured to operate in 298 * cooked mode, and with XTABS CRMOD enabled (see tty(4)). */ 299 tcgetattr(0, &termbuf); 300 termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */ 301 termbuf.c_oflag |= ONLCR|XTABS; 302 termbuf.c_iflag |= ICRNL; 303 termbuf.c_iflag &= ~IXOFF; 304 /*termbuf.c_lflag &= ~ICANON;*/ 305 tcsetattr(0, TCSANOW, &termbuf); 306 307 print_login_issue(issuefile, NULL); 308 309 /* exec shell / login /whatever */ 310 login_argv[0] = loginpath; 311 login_argv[1] = NULL; 312 execv(loginpath, (char **)login_argv); 313 /* Hmmm... this gets sent to the client thru fd#2! Is it ok?? */ 314 bb_perror_msg_and_die("execv %s", loginpath); 346 315 } 347 316 348 #ifndef CONFIG_FEATURE_TELNETD_INETD 317 #if ENABLE_FEATURE_TELNETD_STANDALONE 318 349 319 static void 350 320 free_session(struct tsession *ts) … … 352 322 struct tsession *t = sessions; 353 323 354 /* Unlink this telnet session from the session list.*/324 /* unlink this telnet session from the session list */ 355 325 if (t == ts) 356 326 sessions = ts->next; 357 327 else { 358 while (t->next != ts)328 while (t->next != ts) 359 329 t = t->next; 360 330 t->next = ts->next; … … 362 332 363 333 kill(ts->shell_pid, SIGKILL); 364 365 334 wait4(ts->shell_pid, NULL, 0, NULL); 366 367 335 close(ts->ptyfd); 368 close(ts->sockfd); 369 370 if (ts->ptyfd == maxfd || ts->sockfd == maxfd) 371 maxfd--; 372 if (ts->ptyfd == maxfd || ts->sockfd == maxfd) 373 maxfd--; 374 336 close(ts->sockfd_read); 337 /* error if ts->sockfd_read == ts->sockfd_write. So what? ;) */ 338 close(ts->sockfd_write); 375 339 free(ts); 340 341 /* scan all sessions and find new maxfd */ 342 ts = sessions; 343 maxfd = 0; 344 while (ts) { 345 if (maxfd < ts->ptyfd) 346 maxfd = ts->ptyfd; 347 if (maxfd < ts->sockfd_read) 348 maxfd = ts->sockfd_read; 349 if (maxfd < ts->sockfd_write) 350 maxfd = ts->sockfd_write; 351 ts = ts->next; 352 } 376 353 } 377 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 378 379 int 380 telnetd_main(int argc, char **argv) 354 355 #else /* !FEATURE_TELNETD_STANDALONE */ 356 357 /* Never actually called */ 358 void free_session(struct tsession *ts); 359 360 #endif 361 362 363 int telnetd_main(int argc, char **argv); 364 int telnetd_main(int argc, char **argv) 381 365 { 382 #ifndef CONFIG_FEATURE_TELNETD_INETD383 sockaddr_type sa;384 int master_fd;385 #endif /* CONFIG_FEATURE_TELNETD_INETD */386 366 fd_set rdfdset, wrfdset; 387 int selret;388 #ifndef CONFIG_FEATURE_TELNETD_INETD 389 int on = 1;390 int portnbr = 23; 391 struct in_addr bind_addr = { .s_addr = 0x0 }; 392 #endif /* CONFIG_FEATURE_TELNETD_INETD*/393 int c;394 static const char options[] =395 #ifdef CONFIG_FEATURE_TELNETD_INETD 396 "f:l:"; 397 #else /* CONFIG_EATURE_TELNETD_INETD */ 398 "f:l:p:b:";399 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 400 int maxlen, w, r;401 402 # ifndef CONFIG_LOGIN403 loginpath = DEFAULT_SHELL;404 #endif 405 406 for (;;) {407 c = getopt( argc, argv, options);408 if (c == EOF) break; 409 switch (c) {410 case 'f':411 issuefile = optarg;412 break;413 case 'l':414 loginpath = optarg;415 break;416 #ifndef CONFIG_FEATURE_TELNETD_INETD 417 case 'p':418 portnbr = atoi(optarg);419 break;420 case 'b':421 if (inet_aton(optarg, &bind_addr) == 0)422 bb_show_usage();423 break;424 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 425 default:426 bb_show_usage(); 427 }428 }429 430 if (access(loginpath, X_OK) < 0) { 431 bb_error_msg_and_die ("'%s' unavailable.", loginpath);432 }433 434 argv_init[0] = loginpath;435 436 openlog(bb_applet_name, 0, LOG_USER);437 438 #ifdef CONFIG_FEATURE_TELNETD_INETD 439 maxfd = 1; 367 unsigned opt; 368 int selret, maxlen, w, r; 369 struct tsession *ts; 370 #if ENABLE_FEATURE_TELNETD_STANDALONE 371 #define IS_INETD (opt & OPT_INETD) 372 int master_fd = -1; /* be happy, gcc */ 373 unsigned portnbr = 23; 374 char *opt_bindaddr = NULL; 375 char *opt_portnbr; 376 #else 377 enum { 378 IS_INETD = 1, 379 master_fd = -1, 380 portnbr = 23, 381 }; 382 #endif 383 enum { 384 OPT_PORT = 4 * ENABLE_FEATURE_TELNETD_STANDALONE, 385 OPT_FOREGROUND = 0x10 * ENABLE_FEATURE_TELNETD_STANDALONE, 386 OPT_INETD = 0x20 * ENABLE_FEATURE_TELNETD_STANDALONE, 387 }; 388 389 opt = getopt32(argv, "f:l:" USE_FEATURE_TELNETD_STANDALONE("p:b:Fi"), 390 &issuefile, &loginpath 391 USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)); 392 /* Redirect log to syslog early, if needed */ 393 if (IS_INETD || !(opt & OPT_FOREGROUND)) { 394 openlog(applet_name, 0, LOG_USER); 395 logmode = LOGMODE_SYSLOG; 396 } 397 //if (opt & 1) // -f 398 //if (opt & 2) // -l 399 USE_FEATURE_TELNETD_STANDALONE( 400 if (opt & OPT_PORT) // -p 401 portnbr = xatou16(opt_portnbr); 402 //if (opt & 8) // -b 403 //if (opt & 0x10) // -F 404 //if (opt & 0x20) // -i 405 ); 406 407 /* Used to check access(loginpath, X_OK) here. Pointless. 408 * exec will do this for us for free later. */ 409 410 #if ENABLE_FEATURE_TELNETD_STANDALONE 411 if (IS_INETD) { 412 sessions = make_new_session(0, 1); 413 } else { 414 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr); 415 xlisten(master_fd, 1); 416 if (!(opt & OPT_FOREGROUND)) 417 bb_daemonize(DAEMON_CHDIR_ROOT); 418 } 419 #else 440 420 sessions = make_new_session(); 441 #else /* CONFIG_EATURE_TELNETD_INETD */ 442 sessions = 0; 443 444 /* Grab a TCP socket. */ 445 446 master_fd = bb_xsocket(SOCKET_TYPE, SOCK_STREAM, 0); 447 (void)setsockopt(master_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 448 449 /* Set it to listen to specified port. */ 450 451 memset((void *)&sa, 0, sizeof(sa)); 452 #ifdef CONFIG_FEATURE_IPV6 453 sa.sin6_family = AF_INET6; 454 sa.sin6_port = htons(portnbr); 455 /* sa.sin6_addr = bind_addr6; */ 456 #else 457 sa.sin_family = AF_INET; 458 sa.sin_port = htons(portnbr); 459 sa.sin_addr = bind_addr; 460 #endif 461 462 bb_xbind(master_fd, (struct sockaddr *) &sa, sizeof(sa)); 463 bb_xlisten(master_fd, 1); 464 bb_xdaemon(0, 0); 465 466 maxfd = master_fd; 467 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 468 469 do { 470 struct tsession *ts; 471 472 FD_ZERO(&rdfdset); 473 FD_ZERO(&wrfdset); 474 475 /* select on the master socket, all telnet sockets and their 476 * ptys if there is room in their respective session buffers. 477 */ 478 479 #ifndef CONFIG_FEATURE_TELNETD_INETD 421 #endif 422 423 /* We don't want to die if just one session is broken */ 424 signal(SIGPIPE, SIG_IGN); 425 426 again: 427 FD_ZERO(&rdfdset); 428 FD_ZERO(&wrfdset); 429 if (!IS_INETD) { 480 430 FD_SET(master_fd, &rdfdset); 481 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 482 483 ts = sessions; 484 #ifndef CONFIG_FEATURE_TELNETD_INETD 485 while (ts) { 486 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 487 /* buf1 is used from socket to pty 488 * buf2 is used from pty to socket 489 */ 490 if (ts->size1 > 0) { 491 FD_SET(ts->ptyfd, &wrfdset); /* can write to pty */ 492 } 493 if (ts->size1 < BUFSIZE) { 494 #ifdef CONFIG_FEATURE_TELNETD_INETD 495 FD_SET(ts->sockfd_read, &rdfdset); /* can read from socket */ 496 #else /* CONFIG_FEATURE_TELNETD_INETD */ 497 FD_SET(ts->sockfd, &rdfdset); /* can read from socket */ 498 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 499 } 500 if (ts->size2 > 0) { 501 #ifdef CONFIG_FEATURE_TELNETD_INETD 502 FD_SET(ts->sockfd_write, &wrfdset); /* can write to socket */ 503 #else /* CONFIG_FEATURE_TELNETD_INETD */ 504 FD_SET(ts->sockfd, &wrfdset); /* can write to socket */ 505 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 506 } 507 if (ts->size2 < BUFSIZE) { 508 FD_SET(ts->ptyfd, &rdfdset); /* can read from pty */ 509 } 510 #ifndef CONFIG_FEATURE_TELNETD_INETD 511 ts = ts->next; 512 } 513 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 514 515 selret = select(maxfd + 1, &rdfdset, &wrfdset, 0, 0); 516 517 if (!selret) 518 break; 519 520 #ifndef CONFIG_FEATURE_TELNETD_INETD 521 /* First check for and accept new sessions. */ 522 if (FD_ISSET(master_fd, &rdfdset)) { 523 int fd; 524 socklen_t salen; 525 526 salen = sizeof(sa); 527 if ((fd = accept(master_fd, (struct sockaddr *)&sa, 528 &salen)) < 0) { 431 /* This is needed because free_session() does not 432 * take into account master_fd when it finds new 433 * maxfd among remaining fd's: */ 434 if (master_fd > maxfd) 435 maxfd = master_fd; 436 } 437 438 /* select on the master socket, all telnet sockets and their 439 * ptys if there is room in their session buffers. */ 440 ts = sessions; 441 while (ts) { 442 /* buf1 is used from socket to pty 443 * buf2 is used from pty to socket */ 444 if (ts->size1 > 0) /* can write to pty */ 445 FD_SET(ts->ptyfd, &wrfdset); 446 if (ts->size1 < BUFSIZE) /* can read from socket */ 447 FD_SET(ts->sockfd_read, &rdfdset); 448 if (ts->size2 > 0) /* can write to socket */ 449 FD_SET(ts->sockfd_write, &wrfdset); 450 if (ts->size2 < BUFSIZE) /* can read from pty */ 451 FD_SET(ts->ptyfd, &rdfdset); 452 ts = ts->next; 453 } 454 455 selret = select(maxfd + 1, &rdfdset, &wrfdset, 0, 0); 456 if (!selret) 457 return 0; 458 459 #if ENABLE_FEATURE_TELNETD_STANDALONE 460 /* First check for and accept new sessions. */ 461 if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) { 462 int fd; 463 struct tsession *new_ts; 464 465 fd = accept(master_fd, NULL, 0); 466 if (fd < 0) 467 goto again; 468 /* Create a new session and link it into our active list */ 469 new_ts = make_new_session(fd, fd); 470 if (new_ts) { 471 new_ts->next = sessions; 472 sessions = new_ts; 473 } else { 474 close(fd); 475 } 476 } 477 #endif 478 479 /* Then check for data tunneling. */ 480 ts = sessions; 481 while (ts) { /* For all sessions... */ 482 struct tsession *next = ts->next; /* in case we free ts. */ 483 484 if (ts->size1 && FD_ISSET(ts->ptyfd, &wrfdset)) { 485 int num_totty; 486 char *ptr; 487 /* Write to pty from buffer 1. */ 488 ptr = remove_iacs(ts, &num_totty); 489 w = safe_write(ts->ptyfd, ptr, num_totty); 490 /* needed? if (w < 0 && errno == EAGAIN) continue; */ 491 if (w < 0) { 492 if (IS_INETD) 493 return 0; 494 free_session(ts); 495 ts = next; 529 496 continue; 530 } else { 531 /* Create a new session and link it into 532 our active list. */ 533 struct tsession *new_ts = make_new_session(fd); 534 if (new_ts) { 535 new_ts->next = sessions; 536 sessions = new_ts; 537 if (fd > maxfd) 538 maxfd = fd; 539 } else { 540 close(fd); 541 } 542 } 543 } 544 545 /* Then check for data tunneling. */ 546 547 ts = sessions; 548 while (ts) { /* For all sessions... */ 549 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 550 #ifndef CONFIG_FEATURE_TELNETD_INETD 551 struct tsession *next = ts->next; /* in case we free ts. */ 552 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 553 554 if (ts->size1 && FD_ISSET(ts->ptyfd, &wrfdset)) { 555 int num_totty; 556 char *ptr; 557 /* Write to pty from buffer 1. */ 558 559 ptr = remove_iacs(ts, &num_totty); 560 561 w = write(ts->ptyfd, ptr, num_totty); 562 if (w < 0) { 563 #ifdef CONFIG_FEATURE_TELNETD_INETD 564 exit(0); 565 #else /* CONFIG_FEATURE_TELNETD_INETD */ 566 free_session(ts); 567 ts = next; 497 } 498 ts->wridx1 += w; 499 ts->size1 -= w; 500 if (ts->wridx1 == BUFSIZE) 501 ts->wridx1 = 0; 502 } 503 504 if (ts->size2 && FD_ISSET(ts->sockfd_write, &wrfdset)) { 505 /* Write to socket from buffer 2. */ 506 maxlen = MIN(BUFSIZE - ts->wridx2, ts->size2); 507 w = safe_write(ts->sockfd_write, ts->buf2 + ts->wridx2, maxlen); 508 /* needed? if (w < 0 && errno == EAGAIN) continue; */ 509 if (w < 0) { 510 if (IS_INETD) 511 return 0; 512 free_session(ts); 513 ts = next; 514 continue; 515 } 516 ts->wridx2 += w; 517 ts->size2 -= w; 518 if (ts->wridx2 == BUFSIZE) 519 ts->wridx2 = 0; 520 } 521 522 if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd_read, &rdfdset)) { 523 /* Read from socket to buffer 1. */ 524 maxlen = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1); 525 r = safe_read(ts->sockfd_read, ts->buf1 + ts->rdidx1, maxlen); 526 if (r < 0 && errno == EAGAIN) continue; 527 if (r <= 0) { 528 if (IS_INETD) 529 return 0; 530 free_session(ts); 531 ts = next; 532 continue; 533 } 534 if (!ts->buf1[ts->rdidx1 + r - 1]) 535 if (!--r) 568 536 continue; 569 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 570 } 571 ts->wridx1 += w; 572 ts->size1 -= w; 573 if (ts->wridx1 == BUFSIZE) 574 ts->wridx1 = 0; 575 } 576 577 #ifdef CONFIG_FEATURE_TELNETD_INETD 578 if (ts->size2 && FD_ISSET(ts->sockfd_write, &wrfdset)) { 579 #else /* CONFIG_FEATURE_TELNETD_INETD */ 580 if (ts->size2 && FD_ISSET(ts->sockfd, &wrfdset)) { 581 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 582 /* Write to socket from buffer 2. */ 583 maxlen = MIN(BUFSIZE - ts->wridx2, ts->size2); 584 #ifdef CONFIG_FEATURE_TELNETD_INETD 585 w = write(ts->sockfd_write, ts->buf2 + ts->wridx2, maxlen); 586 if (w < 0) 587 exit(0); 588 #else /* CONFIG_FEATURE_TELNETD_INETD */ 589 w = write(ts->sockfd, ts->buf2 + ts->wridx2, maxlen); 590 if (w < 0) { 591 free_session(ts); 592 ts = next; 593 continue; 594 } 595 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 596 ts->wridx2 += w; 597 ts->size2 -= w; 598 if (ts->wridx2 == BUFSIZE) 599 ts->wridx2 = 0; 600 } 601 602 #ifdef CONFIG_FEATURE_TELNETD_INETD 603 if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd_read, &rdfdset)) { 604 #else /* CONFIG_FEATURE_TELNETD_INETD */ 605 if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd, &rdfdset)) { 606 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 607 /* Read from socket to buffer 1. */ 608 maxlen = MIN(BUFSIZE - ts->rdidx1, 609 BUFSIZE - ts->size1); 610 #ifdef CONFIG_FEATURE_TELNETD_INETD 611 r = read(ts->sockfd_read, ts->buf1 + ts->rdidx1, maxlen); 612 if (!r || (r < 0 && errno != EINTR)) 613 exit(0); 614 #else /* CONFIG_FEATURE_TELNETD_INETD */ 615 r = read(ts->sockfd, ts->buf1 + ts->rdidx1, maxlen); 616 if (!r || (r < 0 && errno != EINTR)) { 617 free_session(ts); 618 ts = next; 619 continue; 620 } 621 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 622 if (!*(ts->buf1 + ts->rdidx1 + r - 1)) { 623 r--; 624 if (!r) 625 continue; 626 } 627 ts->rdidx1 += r; 628 ts->size1 += r; 629 if (ts->rdidx1 == BUFSIZE) 630 ts->rdidx1 = 0; 631 } 632 633 if (ts->size2 < BUFSIZE && FD_ISSET(ts->ptyfd, &rdfdset)) { 634 /* Read from pty to buffer 2. */ 635 maxlen = MIN(BUFSIZE - ts->rdidx2, 636 BUFSIZE - ts->size2); 637 r = read(ts->ptyfd, ts->buf2 + ts->rdidx2, maxlen); 638 if (!r || (r < 0 && errno != EINTR)) { 639 #ifdef CONFIG_FEATURE_TELNETD_INETD 640 exit(0); 641 #else /* CONFIG_FEATURE_TELNETD_INETD */ 642 free_session(ts); 643 ts = next; 644 continue; 645 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 646 } 647 ts->rdidx2 += r; 648 ts->size2 += r; 649 if (ts->rdidx2 == BUFSIZE) 650 ts->rdidx2 = 0; 651 } 652 653 if (ts->size1 == 0) { 537 ts->rdidx1 += r; 538 ts->size1 += r; 539 if (ts->rdidx1 == BUFSIZE) 654 540 ts->rdidx1 = 0; 655 ts->wridx1 = 0; 656 } 657 if (ts->size2 == 0) { 541 } 542 543 if (ts->size2 < BUFSIZE && FD_ISSET(ts->ptyfd, &rdfdset)) { 544 /* Read from pty to buffer 2. */ 545 maxlen = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2); 546 r = safe_read(ts->ptyfd, ts->buf2 + ts->rdidx2, maxlen); 547 if (r < 0 && errno == EAGAIN) continue; 548 if (r <= 0) { 549 if (IS_INETD) 550 return 0; 551 free_session(ts); 552 ts = next; 553 continue; 554 } 555 ts->rdidx2 += r; 556 ts->size2 += r; 557 if (ts->rdidx2 == BUFSIZE) 658 558 ts->rdidx2 = 0; 659 ts->wridx2 = 0; 660 } 661 #ifndef CONFIG_FEATURE_TELNETD_INETD 662 ts = next; 663 } 664 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 665 666 } while (1); 667 668 return 0; 559 } 560 561 if (ts->size1 == 0) { 562 ts->rdidx1 = 0; 563 ts->wridx1 = 0; 564 } 565 if (ts->size2 == 0) { 566 ts->rdidx2 = 0; 567 ts->wridx2 = 0; 568 } 569 ts = next; 570 } 571 goto again; 669 572 }
Note:
See TracChangeset
for help on using the changeset viewer.