Ejemplo n.º 1
0
/* 
   Remove all IAC's from the buffer pointed to by bf (recieved IACs are ignored
   and must be removed so as to not be interpreted by the terminal).  Make an
   uninterrupted string of characters fit for the terminal.  Do this by packing
   all characters meant for the terminal sequentially towards the end of bf. 

   Return a pointer to the beginning of the characters meant for the terminal.
   and make *processed equal to the number of characters that were actually
   processed and *num_totty the number of characters that should be sent to
   the terminal.  
   
   Note - If an IAC (3 byte quantity) starts before (bf + len) but extends
   past (bf + len) then that IAC will be left unprocessed and *processed will be
   less than len.
  
   FIXME - if we mean to send 0xFF to the terminal then it will be escaped,
   what is the escape character?  We aren't handling that situation here.

  */
static char *
remove_iacs(unsigned char *bf, int len, int *processed, int *num_totty) {
    unsigned char *ptr = bf;
    unsigned char *totty = bf;
    unsigned char *end = bf + len;
   
    while (ptr < end) {
	if (*ptr != IAC) {
	    *totty++ = *ptr++;
	}
	else {
	    if ((ptr+2) < end) {
		/* the entire IAC is contained in the buffer 
		   we were asked to process. */
		DEBUG_OUT("Ignoring IAC 0x%02x, %s, %s\n", *ptr, TELCMD(*(ptr+1)), TELOPT(*(ptr+2)));
		ptr += 3;
	    } else {
		/* only the beginning of the IAC is in the 
		   buffer we were asked to process, we can't
		   process this char. */
		break;
	    }
	}
    }

    *processed = ptr - bf;
    *num_totty = totty - bf;
    /* move the chars meant for the terminal towards the end of the 
       buffer. */
    return memmove(ptr - *num_totty, bf, *num_totty);
}
Ejemplo n.º 2
0
void
printoption(const char *direction, int cmd, int option)
{
	if (!showoptions)
		return;
	if (cmd == IAC) {
		if (TELCMD_OK(option))
		    fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option));
		else
		    fprintf(NetTrace, "%s IAC %d", direction, option);
	} else {
		const char *fmt;
		fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
			(cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
		if (fmt) {
		    fprintf(NetTrace, "%s %s ", direction, fmt);
		    if (TELOPT_OK(option))
			fprintf(NetTrace, "%s", TELOPT(option));
		    else if (option == TELOPT_EXOPL)
			fprintf(NetTrace, "EXOPL");
		    else
			fprintf(NetTrace, "%d", option);
		} else
		    fprintf(NetTrace, "%s %d %d", direction, cmd, option);
	}
	if (NetTrace == stdout) {
	    fprintf(NetTrace, "\r\n");
	    fflush(NetTrace);
	} else {
	    fprintf(NetTrace, "\n");
	}
	return;
}
Ejemplo n.º 3
0
void handle_telnet(const unsigned char *bytes, uint16_t frame_len) {
    print1("TELNET  ");
    print_ips_from_last_header_v1();
    printf1("%u bytes\n", frame_len);

    const unsigned char *end = bytes + frame_len;

    while(bytes < end) {
        if(*bytes & 0xFF) {
            bytes++;
            uint8_t command = *bytes++;
            printf3("        cmd %s (%u): ", TELCMD_OK(command) ? TELCMD(command) : "CMD?", command);
            switch(command) {
                case DO:
                case DONT:
                case WONT:
                case WILL: {
                    uint8_t option = *bytes++;
                    printf3("%s (%u)", TELOPT(option), option);
                    break;
                }
                case SB: {
                    uint8_t suboption = *bytes++;
                    printf3("%s (%u)", TELOPT(suboption), suboption);
                    switch(suboption) {
                        case TELOPT_TSPEED:
                            printf3(" = %u", *bytes++);
                            break;
                        case TELOPT_NAWS:
                            printf3(" = %u x %u", ntohs(*(uint16_t*)&bytes[0]), ntohs(*(uint16_t*)&bytes[2]));
                            bytes += 4;
                            break;
                        default:
                            break;
                    }
                    break;
                }
                case SE:
                    print3("end of suboptions");
                    break;
                default:
                    print3("unknown command");
                    break;
            }
            putchar3('\n');
            if(command == SE)
                break; // end of options
        }
        else {
            bytes++;
        }
    }
}
Ejemplo n.º 4
0
/* Write some buf1 data to pty, processing IACs.
 * Update wridx1 and size1. Return < 0 on error.
 * Buggy if IAC is present but incomplete: skips them.
 */
static ssize_t
safe_write_to_pty_decode_iac(struct tsession *ts)
{
	unsigned wr;
	ssize_t rc;
	unsigned char *buf;
	unsigned char *found;

	buf = TS_BUF1(ts) + ts->wridx1;
	wr = MIN(BUFSIZE - ts->wridx1, ts->size1);
	/* wr is at least 1 here */

	if (ts->buffered_IAC_for_pty) {
		/* Last time we stopped on a "dangling" IAC byte.
		 * We removed it from the buffer back then.
		 * Now pretend it's still there, and jump to IAC processing.
		 */
		ts->buffered_IAC_for_pty = 0;
		wr++;
		ts->size1++;
		buf--; /* Yes, this can point before the buffer. It's ok */
		ts->wridx1--;
		goto handle_iac;
	}

	found = memchr(buf, IAC, wr);
	if (found != buf) {
		/* There is a "prefix" of non-IAC chars.
		 * Write only them, and return.
		 */
		if (found)
			wr = found - buf;

		/* We map \r\n ==> \r for pragmatic reasons:
		 * many client implementations send \r\n when
		 * the user hits the CarriageReturn key.
		 * See RFC 1123 3.3.1 Telnet End-of-Line Convention.
		 */
		rc = wr;
		found = memchr(buf, '\r', wr);
		if (found)
			rc = found - buf + 1;
		rc = safe_write(ts->ptyfd, buf, rc);
		if (rc <= 0)
			return rc;
		if (rc < wr /* don't look past available data */
		 && buf[rc-1] == '\r' /* need this: imagine that write was _short_ */
		 && (buf[rc] == '\n' || buf[rc] == '\0')
		) {
			rc++;
		}
		goto update_and_return;
	}

	/* buf starts with IAC char. Process that sequence.
	 * Example: we get this from our own (bbox) telnet client:
	 * read(5, "\377\374\1""\377\373\37""\377\372\37\0\262\0@\377\360""\377\375\1""\377\375\3"):
	 * IAC WONT ECHO, IAC WILL NAWS, IAC SB NAWS <cols> <rows> IAC SE, IAC DO SGA
	 * Another example (telnet-0.17 from old-netkit):
	 * read(4, "\377\375\3""\377\373\30""\377\373\37""\377\373 ""\377\373!""\377\373\"""\377\373'"
	 * "\377\375\5""\377\373#""\377\374\1""\377\372\37\0\257\0I\377\360""\377\375\1"):
	 * IAC DO SGA, IAC WILL TTYPE, IAC WILL NAWS, IAC WILL TSPEED, IAC WILL LFLOW, IAC WILL LINEMODE, IAC WILL NEW_ENVIRON,
	 * IAC DO STATUS, IAC WILL XDISPLOC, IAC WONT ECHO, IAC SB NAWS <cols> <rows> IAC SE, IAC DO ECHO
	 */
	if (wr <= 1) {
		/* Only the single IAC byte is in the buffer, eat it
		 * and set a flag "process the rest of the sequence
		 * next time we are here".
		 */
		//bb_error_msg("dangling IAC!");
		ts->buffered_IAC_for_pty = 1;
		rc = 1;
		goto update_and_return;
	}

 handle_iac:
	/* 2-byte commands (240..250 and 255):
	 * IAC IAC (255) Literal 255. Supported.
	 * IAC SE  (240) End of subnegotiation. Treated as NOP.
	 * IAC NOP (241) NOP. Supported.
	 * IAC BRK (243) Break. Like serial line break. TODO via tcsendbreak()?
	 * IAC AYT (246) Are you there. Send back evidence that AYT was seen. TODO (send NOP back)?
	 *  These don't look useful:
	 * IAC DM  (242) Data mark. What is this?
	 * IAC IP  (244) Suspend, interrupt or abort the process. (Ancient cousin of ^C).
	 * IAC AO  (245) Abort output. "You can continue running, but do not send me the output".
	 * IAC EC  (247) Erase character. The receiver should delete the last received char.
	 * IAC EL  (248) Erase line. The receiver should delete everything up tp last newline.
	 * IAC GA  (249) Go ahead. For half-duplex lines: "now you talk".
	 *  Implemented only as part of NAWS:
	 * IAC SB  (250) Subnegotiation of an option follows.
	 */
	if (buf[1] == IAC) {
		/* Literal 255 (emacs M-DEL) */
		//bb_error_msg("255!");
		rc = safe_write(ts->ptyfd, &buf[1], 1);
		/*
		 * If we went through buffered_IAC_for_pty==1 path,
		 * bailing out on error like below messes up the buffer.
		 * EAGAIN is highly unlikely here, other errors will be
		 * repeated on next write, let's just skip error check.
		 */
#if 0
		if (rc <= 0)
			return rc;
#endif
		rc = 2;
		goto update_and_return;
	}
	if (buf[1] >= 240 && buf[1] <= 249) {
		/* NOP (241). Ignore (putty keepalive, etc) */
		/* All other 2-byte commands also treated as NOPs here */
		rc = 2;
		goto update_and_return;
	}

	if (wr <= 2) {
/* BUG: only 2 bytes of the IAC is in the buffer, we just eat them.
 * This is not a practical problem since >2 byte IACs are seen only
 * in initial negotiation, when buffer is empty
 */
		rc = 2;
		goto update_and_return;
	}

	if (buf[1] == SB) {
		if (buf[2] == TELOPT_NAWS) {
			/* IAC SB, TELOPT_NAWS, 4-byte, IAC SE */
			struct winsize ws;
			if (wr <= 6) {
/* BUG: incomplete, can't process */
				rc = wr;
				goto update_and_return;
			}
			memset(&ws, 0, sizeof(ws)); /* pixel sizes are set to 0 */
			ws.ws_col = (buf[3] << 8) | buf[4];
			ws.ws_row = (buf[5] << 8) | buf[6];
			ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
			rc = 7;
			/* trailing IAC SE will be eaten separately, as 2-byte NOP */
			goto update_and_return;
		}
		/* else: other subnegs not supported yet */
	}

	/* Assume it is a 3-byte WILL/WONT/DO/DONT 251..254 command and skip it */
#if DEBUG
	fprintf(stderr, "Ignoring IAC %s,%s\n",
			TELCMD(buf[1]), TELOPT(buf[2]));
#endif
	rc = 3;

 update_and_return:
	ts->wridx1 += rc;
	if (ts->wridx1 >= BUFSIZE) /* actually == BUFSIZE */
		ts->wridx1 = 0;
	ts->size1 -= rc;
	/*
	 * Hack. We cannot process IACs which wrap around buffer's end.
	 * Since properly fixing it requires writing bigger code,
	 * we rely instead on this code making it virtually impossible
	 * to have wrapped IAC (people don't type at 2k/second).
	 * It also allows for bigger reads in common case.
	 */
	if (ts->size1 == 0) { /* very typical */
		//bb_error_msg("zero size1");
		ts->rdidx1 = 0;
		ts->wridx1 = 0;
		return rc;
	}
	wr = ts->wridx1;
	if (wr != 0 && wr < ts->rdidx1) {
		/* Buffer is not wrapped yet.
		 * We can easily move it to the beginning.
		 */
		//bb_error_msg("moved %d", wr);
		memmove(TS_BUF1(ts), TS_BUF1(ts) + wr, ts->size1);
		ts->rdidx1 -= wr;
		ts->wridx1 = 0;
	}
	return rc;
}
Ejemplo n.º 5
0
/*
   Remove all IAC's from buf1 (received IACs are ignored and must be removed
   so as to not be interpreted by the terminal).  Make an uninterrupted
   string of characters fit for the terminal.  Do this by packing
   all characters meant for the terminal sequentially towards the end of buf.

   Return a pointer to the beginning of the characters meant for the terminal
   and make *num_totty the number of characters that should be sent to
   the terminal.

   Note - if an IAC (3 byte quantity) starts before (bf + len) but extends
   past (bf + len) then that IAC will be left unprocessed and *processed
   will be less than len.

   CR-LF ->'s CR mapping is also done here, for convenience.

   NB: may fail to remove iacs which wrap around buffer!
 */
static unsigned char *
remove_iacs(struct tsession *ts, int *pnum_totty)
{
	unsigned char *ptr0 = TS_BUF1(ts) + ts->wridx1;
	unsigned char *ptr = ptr0;
	unsigned char *totty = ptr;
	unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1);
	int num_totty;

	while (ptr < end) {
		if (*ptr != IAC) {
			char c = *ptr;

			*totty++ = c;
			ptr++;
			/* We map \r\n ==> \r for pragmatic reasons.
			 * Many client implementations send \r\n when
			 * the user hits the CarriageReturn key.
			 * See RFC 1123 3.3.1 Telnet End-of-Line Convention.
			 */
			if (c == '\r' && ptr < end && (*ptr == '\n' || *ptr == '\0'))
				ptr++;
			continue;
		}

		if ((ptr+1) >= end)
			break;
		if (ptr[1] == NOP) { /* Ignore? (putty keepalive, etc.) */
			ptr += 2;
			continue;
		}
		if (ptr[1] == IAC) { /* Literal IAC? (emacs M-DEL) */
			*totty++ = ptr[1];
			ptr += 2;
			continue;
		}

		/*
		 * TELOPT_NAWS support!
		 */
		if ((ptr+2) >= end) {
			/* Only the beginning of the IAC is in the
			buffer we were asked to process, we can't
			process this char */
			break;
		}
		/*
		 * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE
		 */
		if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) {
			struct winsize ws;
			if ((ptr+8) >= end)
				break;  /* incomplete, can't process */
			ws.ws_col = (ptr[3] << 8) | ptr[4];
			ws.ws_row = (ptr[5] << 8) | ptr[6];
			ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
			ptr += 9;
			continue;
		}
		/* skip 3-byte IAC non-SB cmd */
#if DEBUG
		fprintf(stderr, "Ignoring IAC %s,%s\n",
				TELCMD(ptr[1]), TELOPT(ptr[2]));
#endif
		ptr += 3;
	}

	num_totty = totty - ptr0;
	*pnum_totty = num_totty;
	/* The difference between ptr and totty is number of iacs
	   we removed from the stream. Adjust buf1 accordingly */
	if ((ptr - totty) == 0) /* 99.999% of cases */
		return ptr0;
	ts->wridx1 += ptr - totty;
	ts->size1 -= ptr - totty;
	/* Move chars meant for the terminal towards the end of the buffer */
	return memmove(ptr - num_totty, ptr0, num_totty);
}
Ejemplo n.º 6
0
/*

   Remove all IAC's from the buffer pointed to by bf (recieved IACs are ignored
   and must be removed so as to not be interpreted by the terminal).  Make an
   uninterrupted string of characters fit for the terminal.  Do this by packing
   all characters meant for the terminal sequentially towards the end of bf.

   Return a pointer to the beginning of the characters meant for the terminal.
   and make *num_totty the number of characters that should be sent to
   the terminal.

   Note - If an IAC (3 byte quantity) starts before (bf + len) but extends
   past (bf + len) then that IAC will be left unprocessed and *processed will be
   less than len.

   FIXME - if we mean to send 0xFF to the terminal then it will be escaped,
   what is the escape character?  We aren't handling that situation here.

   CR-LF ->'s CR mapping is also done here, for convenience

  */
static char *
remove_iacs(struct tsession *ts, int *pnum_totty) {
	unsigned char *ptr0 = ts->buf1 + ts->wridx1;
	unsigned char *ptr = ptr0;
	unsigned char *totty = ptr;
	unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1);
	int processed;
	int num_totty;

	while (ptr < end) {
		if (*ptr != IAC) {
			int c = *ptr;
			*totty++ = *ptr++;
			/* We now map \r\n ==> \r for pragmatic reasons.
			 * Many client implementations send \r\n when
			 * the user hits the CarriageReturn key.
			 */
			if (c == '\r' && (*ptr == '\n' || *ptr == 0) && ptr < end)
				ptr++;
		}
		else {
			/*
			 * TELOPT_NAWS support!
			 */
			if ((ptr+2) >= end) {
				/* only the beginning of the IAC is in the
				buffer we were asked to process, we can't
				process this char. */
				break;
			}

			/*
			 * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE
			 */
			else if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) {
				struct winsize ws;
				if ((ptr+8) >= end)
					break; 	/* incomplete, can't process */
				ws.ws_col = (ptr[3] << 8) | ptr[4];
				ws.ws_row = (ptr[5] << 8) | ptr[6];
				(void) ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
				ptr += 9;
			}
			else {
				/* skip 3-byte IAC non-SB cmd */
#ifdef DEBUG
				fprintf(stderr, "Ignoring IAC %s,%s\n",
					TELCMD(*(ptr+1)), TELOPT(*(ptr+2)));
#endif
				ptr += 3;
			}
		}
	}

	processed = ptr - ptr0;
	num_totty = totty - ptr0;
	/* the difference between processed and num_to tty
	   is all the iacs we removed from the stream.
	   Adjust buf1 accordingly. */
	ts->wridx1 += processed - num_totty;
	ts->size1 -= processed - num_totty;
	*pnum_totty = num_totty;
	/* move the chars meant for the terminal towards the end of the
	buffer. */
	return memmove(ptr - num_totty, ptr0, num_totty);
}
Ejemplo n.º 7
0
/* int		  length; length of suboption data */
void
printsub (char direction, unsigned char *pointer, int length)
{
  register int i;
  extern int want_status_response;

#if defined AUTHENTICATION || defined ENCRYPTION
  char buf[512];
#endif

  if (showoptions || direction == 0 ||
      (want_status_response && (pointer[0] == TELOPT_STATUS)))
    {
      if (direction)
	{
	  fprintf (NetTrace, "%s IAC SB ",
		   (direction == '<') ? "RCVD" : "SENT");
	  if (length >= 3)
	    {
	      register int j;

	      i = pointer[length - 2];
	      j = pointer[length - 1];

	      if (i != IAC || j != SE)
		{
		  fprintf (NetTrace, "(terminated by ");
		  if (TELOPT_OK (i))
		    fprintf (NetTrace, "%s ", TELOPT (i));
		  else if (TELCMD_OK (i))
		    fprintf (NetTrace, "%s ", TELCMD (i));
		  else
		    fprintf (NetTrace, "%d ", i);
		  if (TELOPT_OK (j))
		    fprintf (NetTrace, "%s", TELOPT (j));
		  else if (TELCMD_OK (j))
		    fprintf (NetTrace, "%s", TELCMD (j));
		  else
		    fprintf (NetTrace, "%d", j);
		  fprintf (NetTrace, ", not IAC SE!) ");
		}
	    }
	  length -= 2;
	}
      if (length < 1)
	{
	  fprintf (NetTrace, "(Empty suboption??\?)");
	  if (NetTrace == stdout)
	    fflush (NetTrace);
	  return;
	}
      switch (pointer[0])
	{
	case TELOPT_TTYPE:
	  fprintf (NetTrace, "TERMINAL-TYPE ");
	  switch (pointer[1])
	    {
	    case TELQUAL_IS:
	      fprintf (NetTrace, "IS \"%.*s\"", length - 2,
		       (char *) pointer + 2);
	      break;
	    case TELQUAL_SEND:
	      fprintf (NetTrace, "SEND");
	      break;
	    default:
	      fprintf (NetTrace, "- unknown qualifier %d (0x%x).",
		       pointer[1], pointer[1]);
	    }
	  break;
	case TELOPT_TSPEED:
	  fprintf (NetTrace, "TERMINAL-SPEED");
	  if (length < 2)
	    {
	      fprintf (NetTrace, " (empty suboption??\?)");
	      break;
	    }
	  switch (pointer[1])
	    {
	    case TELQUAL_IS:
	      fprintf (NetTrace, " IS ");
	      fprintf (NetTrace, "%.*s", length - 2, (char *) pointer + 2);
	      break;
	    default:
	      if (pointer[1] == 1)
		fprintf (NetTrace, " SEND");
	      else
		fprintf (NetTrace, " %d (unknown)", pointer[1]);
	      for (i = 2; i < length; i++)
		fprintf (NetTrace, " ?%d?", pointer[i]);
	      break;
	    }
	  break;

	case TELOPT_LFLOW:
	  fprintf (NetTrace, "TOGGLE-FLOW-CONTROL");
	  if (length < 2)
	    {
	      fprintf (NetTrace, " (empty suboption??\?)");
	      break;
	    }
	  switch (pointer[1])
	    {
	    case LFLOW_OFF:
	      fprintf (NetTrace, " OFF");
	      break;
	    case LFLOW_ON:
	      fprintf (NetTrace, " ON");
	      break;
	    case LFLOW_RESTART_ANY:
	      fprintf (NetTrace, " RESTART-ANY");
	      break;
	    case LFLOW_RESTART_XON:
	      fprintf (NetTrace, " RESTART-XON");
	      break;
	    default:
	      fprintf (NetTrace, " %d (unknown)", pointer[1]);
	    }
	  for (i = 2; i < length; i++)
	    fprintf (NetTrace, " ?%d?", pointer[i]);
	  break;

	case TELOPT_NAWS:
	  fprintf (NetTrace, "NAWS");
	  if (length < 2)
	    {
	      fprintf (NetTrace, " (empty suboption??\?)");
	      break;
	    }
	  if (length == 2)
	    {
	      fprintf (NetTrace, " ?%d?", pointer[1]);
	      break;
	    }
	  fprintf (NetTrace, " %d %d (%d)",
		   pointer[1], pointer[2],
		   (int) ((((unsigned int) pointer[1]) << 8) |
			  ((unsigned int) pointer[2])));
	  if (length == 4)
	    {
	      fprintf (NetTrace, " ?%d?", pointer[3]);
	      break;
	    }
	  fprintf (NetTrace, " %d %d (%d)",
		   pointer[3], pointer[4],
		   (int) ((((unsigned int) pointer[3]) << 8) |
			  ((unsigned int) pointer[4])));
	  for (i = 5; i < length; i++)
	    fprintf (NetTrace, " ?%d?", pointer[i]);
	  break;

#if defined AUTHENTICATION
	case TELOPT_AUTHENTICATION:
	  fprintf (NetTrace, "AUTHENTICATION");
	  if (length < 2)
	    {
	      fprintf (NetTrace, " (empty suboption??\?)");
	      break;
	    }
	  switch (pointer[1])
	    {
	    case TELQUAL_REPLY:
	    case TELQUAL_IS:
	      fprintf (NetTrace, " %s ",
		       (pointer[1] == TELQUAL_IS) ? "IS" : "REPLY");
	      if (AUTHTYPE_NAME_OK (pointer[2]) && AUTHTYPE_NAME (pointer[2]))
		fprintf (NetTrace, "%s ", AUTHTYPE_NAME (pointer[2]));
	      else
		fprintf (NetTrace, "%d ", pointer[2]);
	      if (length < 3)
		{
		  fprintf (NetTrace, "(partial suboption??\?)");
		  break;
		}
	      fprintf (NetTrace, "%s|%s",
		       ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT)
		       ? "CLIENT" : "SERVER",
		       ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
		       ? "MUTUAL" : "ONE-WAY");

	      auth_printsub (&pointer[1], length - 1, buf, sizeof (buf));
	      fprintf (NetTrace, "%s", buf);
	      break;

	    case TELQUAL_SEND:
	      i = 2;
	      fprintf (NetTrace, " SEND ");
	      while (i < length)
		{
		  if (AUTHTYPE_NAME_OK (pointer[i])
		      && AUTHTYPE_NAME (pointer[i]))
		    fprintf (NetTrace, "%s ", AUTHTYPE_NAME (pointer[i]));
		  else
		    fprintf (NetTrace, "%d ", pointer[i]);
		  if (++i >= length)
		    {
		      fprintf (NetTrace, "(partial suboption??\?)");
		      break;
		    }
		  fprintf (NetTrace, "%s|%s ",
			   ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT)
			   ? "CLIENT" : "SERVER",
			   ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
			   ? "MUTUAL" : "ONE-WAY");
		  ++i;
		}
	      break;

	    case TELQUAL_NAME:
	      i = 2;
	      fprintf (NetTrace, " NAME \"");
	      while (i < length)
		putc (pointer[i++], NetTrace);
	      putc ('"', NetTrace);
	      break;

	    default:
	      for (i = 2; i < length; i++)
		fprintf (NetTrace, " ?%d?", pointer[i]);
	      break;
	    }
	  break;
#endif

#ifdef	ENCRYPTION
	case TELOPT_ENCRYPT:
	  fprintf (NetTrace, "ENCRYPT");
	  if (length < 2)
	    {
	      fprintf (NetTrace, " (empty suboption??\?)");
	      break;
	    }
	  switch (pointer[1])
	    {
	    case ENCRYPT_START:
	      fprintf (NetTrace, " START");
	      break;

	    case ENCRYPT_END:
	      fprintf (NetTrace, " END");
	      break;

	    case ENCRYPT_REQSTART:
	      fprintf (NetTrace, " REQUEST-START");
	      break;

	    case ENCRYPT_REQEND:
	      fprintf (NetTrace, " REQUEST-END");
	      break;

	    case ENCRYPT_IS:
	    case ENCRYPT_REPLY:
	      fprintf (NetTrace, " %s ",
		       (pointer[1] == ENCRYPT_IS) ? "IS" : "REPLY");
	      if (length < 3)
		{
		  fprintf (NetTrace, " (partial suboption??\?)");
		  break;
		}
	      if (ENCTYPE_NAME_OK (pointer[2]) && ENCTYPE_NAME (pointer[2]))
		fprintf (NetTrace, "%s ", ENCTYPE_NAME (pointer[2]));
	      else
		fprintf (NetTrace, " %d (unknown)", pointer[2]);

	      encrypt_printsub (&pointer[1], length - 1, buf, sizeof (buf));
	      fprintf (NetTrace, "%s", buf);
	      break;

	    case ENCRYPT_SUPPORT:
	      i = 2;
	      fprintf (NetTrace, " SUPPORT ");
	      while (i < length)
		{
		  if (ENCTYPE_NAME_OK (pointer[i]) && ENCTYPE_NAME (pointer[i]))
		    fprintf (NetTrace, "%s ", ENCTYPE_NAME (pointer[i]));
		  else
		    fprintf (NetTrace, "%d ", pointer[i]);
		  i++;
		}
	      break;

	    case ENCRYPT_ENC_KEYID:
	      fprintf (NetTrace, " ENC_KEYID ");
	      goto encommon;

	    case ENCRYPT_DEC_KEYID:
	      fprintf (NetTrace, " DEC_KEYID ");
	      goto encommon;

	    default:
	      fprintf (NetTrace, " %d (unknown)", pointer[1]);
	    encommon:
	      for (i = 2; i < length; i++)
		fprintf (NetTrace, " %d", pointer[i]);
	      break;
	    }
	  break;
#endif /* ENCRYPTION */

	case TELOPT_LINEMODE:
	  fprintf (NetTrace, "LINEMODE ");
	  if (length < 2)
	    {
	      fprintf (NetTrace, " (empty suboption??\?)");
	      break;
	    }
	  switch (pointer[1])
	    {
	    case WILL:
	      fprintf (NetTrace, "WILL ");
	      goto common;
	    case WONT:
	      fprintf (NetTrace, "WONT ");
	      goto common;
	    case DO:
	      fprintf (NetTrace, "DO ");
	      goto common;
	    case DONT:
	      fprintf (NetTrace, "DONT ");
	    common:
	      if (length < 3)
		{
		  fprintf (NetTrace, "(no option??\?)");
		  break;
		}
	      switch (pointer[2])
		{
		case LM_FORWARDMASK:
		  fprintf (NetTrace, "Forward Mask");
		  for (i = 3; i < length; i++)
		    fprintf (NetTrace, " %x", pointer[i]);
		  break;
		default:
		  fprintf (NetTrace, "%d (unknown)", pointer[2]);
		  for (i = 3; i < length; i++)
		    fprintf (NetTrace, " %d", pointer[i]);
		  break;
		}
	      break;

	    case LM_SLC:
	      fprintf (NetTrace, "SLC");
	      for (i = 2; i < length - 2; i += 3)
		{
		  if (SLC_NAME_OK (pointer[i + SLC_FUNC]))
		    fprintf (NetTrace, " %s",
			     SLC_NAME (pointer[i + SLC_FUNC]));
		  else
		    fprintf (NetTrace, " %d", pointer[i + SLC_FUNC]);
		  switch (pointer[i + SLC_FLAGS] & SLC_LEVELBITS)
		    {
		    case SLC_NOSUPPORT:
		      fprintf (NetTrace, " NOSUPPORT");
		      break;
		    case SLC_CANTCHANGE:
		      fprintf (NetTrace, " CANTCHANGE");
		      break;
		    case SLC_VARIABLE:
		      fprintf (NetTrace, " VARIABLE");
		      break;
		    case SLC_DEFAULT:
		      fprintf (NetTrace, " DEFAULT");
		      break;
		    }
		  fprintf (NetTrace, "%s%s%s",
			   (pointer[i + SLC_FLAGS] & SLC_ACK)
			   ? "|ACK" : "",
			   (pointer[i + SLC_FLAGS] & SLC_FLUSHIN)
			   ? "|FLUSHIN" : "",
			   (pointer[i + SLC_FLAGS] & SLC_FLUSHOUT)
			   ?  "|FLUSHOUT" : "");
		  if (pointer[i + SLC_FLAGS] &
		      ~(SLC_ACK | SLC_FLUSHIN | SLC_FLUSHOUT | SLC_LEVELBITS))
		    fprintf (NetTrace, "(0x%x)", pointer[i + SLC_FLAGS]);
		  fprintf (NetTrace, " %d;", pointer[i + SLC_VALUE]);
		  if ((pointer[i + SLC_VALUE] == IAC) &&
		      (pointer[i + SLC_VALUE + 1] == IAC))
		    i++;
		}
	      for (; i < length; i++)
		fprintf (NetTrace, " ?%d?", pointer[i]);
	      break;

	    case LM_MODE:
	      fprintf (NetTrace, "MODE ");
	      if (length < 3)
		{
		  fprintf (NetTrace, "(no mode??\?)");
		  break;
		}
	      {
		char tbuf[64];
		sprintf (tbuf, "%s%s%s%s%s",
			 pointer[2] & MODE_EDIT ? "|EDIT" : "",
			 pointer[2] & MODE_TRAPSIG ? "|TRAPSIG" : "",
			 pointer[2] & MODE_SOFT_TAB ? "|SOFT_TAB" : "",
			 pointer[2] & MODE_LIT_ECHO ? "|LIT_ECHO" : "",
			 pointer[2] & MODE_ACK ? "|ACK" : "");
		fprintf (NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
	      }
	      if (pointer[2] & ~(MODE_MASK))
		fprintf (NetTrace, " (0x%x)", pointer[2]);
	      for (i = 3; i < length; i++)
		fprintf (NetTrace, " ?0x%x?", pointer[i]);
	      break;
	    default:
	      fprintf (NetTrace, "%d (unknown)", pointer[1]);
	      for (i = 2; i < length; i++)
		fprintf (NetTrace, " %d", pointer[i]);
	    }
	  break;

	case TELOPT_STATUS:
	  {
	    register char *cp;
	    register int j, k;

	    fprintf (NetTrace, "STATUS");

	    switch (pointer[1])
	      {
	      default:
		if (pointer[1] == TELQUAL_SEND)
		  fprintf (NetTrace, " SEND");
		else
		  fprintf (NetTrace, " %d (unknown)", pointer[1]);
		for (i = 2; i < length; i++)
		  fprintf (NetTrace, " ?%d?", pointer[i]);
		break;
	      case TELQUAL_IS:
		if (--want_status_response < 0)
		  want_status_response = 0;
		if (NetTrace == stdout)
		  fprintf (NetTrace, " IS\r\n");
		else
		  fprintf (NetTrace, " IS\n");

		for (i = 2; i < length; i++)
		  {
		    switch (pointer[i])
		      {
		      case DO:
			cp = "DO";
			goto common2;
		      case DONT:
			cp = "DONT";
			goto common2;
		      case WILL:
			cp = "WILL";
			goto common2;
		      case WONT:
			cp = "WONT";
			goto common2;
		      common2:
			i++;
			if (TELOPT_OK ((int) pointer[i]))
			  fprintf (NetTrace, " %s %s", cp,
				   TELOPT (pointer[i]));
			else
			  fprintf (NetTrace, " %s %d", cp, pointer[i]);

			if (NetTrace == stdout)
			  fprintf (NetTrace, "\r\n");
			else
			  fprintf (NetTrace, "\n");
			break;

		      case SB:
			fprintf (NetTrace, " SB ");
			i++;
			j = k = i;
			while (j < length)
			  {
			    if (pointer[j] == SE)
			      {
				if (j + 1 == length)
				  break;
				if (pointer[j + 1] == SE)
				  j++;
				else
				  break;
			      }
			    pointer[k++] = pointer[j++];
			  }
			printsub (0, &pointer[i], k - i);
			if (i < length)
			  {
			    fprintf (NetTrace, " SE");
			    i = j;
			  }
			else
			  i = j - 1;

			if (NetTrace == stdout)
			  fprintf (NetTrace, "\r\n");
			else
			  fprintf (NetTrace, "\n");

			break;

		      default:
			fprintf (NetTrace, " %d", pointer[i]);
			break;
		      }
		  }
		break;
	      }
	    break;
	  }

	case TELOPT_XDISPLOC:
	  fprintf (NetTrace, "X-DISPLAY-LOCATION ");
	  switch (pointer[1])
	    {
	    case TELQUAL_IS:
	      fprintf (NetTrace, "IS \"%.*s\"", length - 2,
		       (char *) pointer + 2);
	      break;
	    case TELQUAL_SEND:
	      fprintf (NetTrace, "SEND");
	      break;
	    default:
	      fprintf (NetTrace, "- unknown qualifier %d (0x%x).",
		       pointer[1], pointer[1]);
	    }
	  break;

	case TELOPT_NEW_ENVIRON:
	  fprintf (NetTrace, "NEW-ENVIRON ");
#ifdef	OLD_ENVIRON
	  goto env_common1;
	case TELOPT_OLD_ENVIRON:
	  fprintf (NetTrace, "OLD-ENVIRON");
	env_common1:
#endif
	  switch (pointer[1])
	    {
	    case TELQUAL_IS:
	      fprintf (NetTrace, "IS ");
	      goto env_common;
	    case TELQUAL_SEND:
	      fprintf (NetTrace, "SEND ");
	      goto env_common;
	    case TELQUAL_INFO:
	      fprintf (NetTrace, "INFO ");
	    env_common:
	      {
		const char *quote = "";
#if defined ENV_HACK && defined OLD_ENVIRON
		extern int old_env_var, old_env_value;
#endif
		for (i = 2; i < length; i++)
		  {
		    switch (pointer[i])
		      {
		      case NEW_ENV_VALUE:
#ifdef OLD_ENVIRON
			/* case NEW_ENV_OVAR: */
			if (pointer[0] == TELOPT_OLD_ENVIRON)
			  {
# ifdef	ENV_HACK
			    if (old_env_var == OLD_ENV_VALUE)
			      fprintf (NetTrace, "%s(VALUE) ", quote);
			    else
# endif
			      fprintf (NetTrace, "%sVAR ", quote);
			  }
			else
#endif /* OLD_ENVIRON */
			  fprintf (NetTrace, "%sVALUE ", quote);
			quote = "";
			break;

		      case NEW_ENV_VAR:
#ifdef OLD_ENVIRON
			/* case OLD_ENV_VALUE: */
			if (pointer[0] == TELOPT_OLD_ENVIRON)
			  {
# ifdef	ENV_HACK
			    if (old_env_value == OLD_ENV_VAR)
			      fprintf (NetTrace, "%s(VAR) ", quote);
			    else
# endif
			      fprintf (NetTrace, "%sVALUE ", quote);
			  }
			else
#endif /* OLD_ENVIRON */
			  fprintf (NetTrace, "%sVAR ", quote);
			quote = "";
			break;

		      case ENV_ESC:
			fprintf (NetTrace, "%sESC ", quote);
			quote = "";
			break;

		      case ENV_USERVAR:
			fprintf (NetTrace, "%sUSERVAR ", quote);
			quote = "";
			break;

		      default:
			if (isprint (pointer[i]) && pointer[i] != '"')
			  {
			    if (quote[0] == '\0')
			      {
				putc ('"', NetTrace);
				quote = "\" ";
			      }
			    putc (pointer[i], NetTrace);
			  }
			else
			  {
			    fprintf (NetTrace, "%s%03o ", quote, pointer[i]);
			    quote = "";
			  }
			break;
		      }
		  }
		if (quote[0] != '\0')
		  putc ('"', NetTrace);
		break;
	      }
	    }
	  break;

	default:
	  if (TELOPT_OK (pointer[0]))
	    fprintf (NetTrace, "%s (unknown)", TELOPT (pointer[0]));
	  else
	    fprintf (NetTrace, "%d (unknown)", pointer[0]);
	  for (i = 1; i < length; i++)
	    fprintf (NetTrace, " %d", pointer[i]);
	  break;
	}
      if (direction)
	{
	  if (NetTrace == stdout)
	    fprintf (NetTrace, "\r\n");
	  else
	    fprintf (NetTrace, "\n");
	}
      if (NetTrace == stdout)
	fflush (NetTrace);
    }
}
Ejemplo n.º 8
0
void
optionstatus (void)
{
  register int i;
  extern char will_wont_resp[], do_dont_resp[];

  for (i = 0; i < 256; i++)
    {
      if (do_dont_resp[i])
	{
	  if (TELOPT_OK (i))
	    printf ("resp DO_DONT %s: %d\n", TELOPT (i), do_dont_resp[i]);
	  else if (TELCMD_OK (i))
	    printf ("resp DO_DONT %s: %d\n", TELCMD (i), do_dont_resp[i]);
	  else
	    printf ("resp DO_DONT %d: %d\n", i, do_dont_resp[i]);
	  if (my_want_state_is_do (i))
	    {
	      if (TELOPT_OK (i))
		printf ("want DO   %s\n", TELOPT (i));
	      else if (TELCMD_OK (i))
		printf ("want DO   %s\n", TELCMD (i));
	      else
		printf ("want DO   %d\n", i);
	    }
	  else
	    {
	      if (TELOPT_OK (i))
		printf ("want DONT %s\n", TELOPT (i));
	      else if (TELCMD_OK (i))
		printf ("want DONT %s\n", TELCMD (i));
	      else
		printf ("want DONT %d\n", i);
	    }
	}
      else
	{
	  if (my_state_is_do (i))
	    {
	      if (TELOPT_OK (i))
		printf ("     DO   %s\n", TELOPT (i));
	      else if (TELCMD_OK (i))
		printf ("     DO   %s\n", TELCMD (i));
	      else
		printf ("     DO   %d\n", i);
	    }
	}
      if (will_wont_resp[i])
	{
	  if (TELOPT_OK (i))
	    printf ("resp WILL_WONT %s: %d\n", TELOPT (i), will_wont_resp[i]);
	  else if (TELCMD_OK (i))
	    printf ("resp WILL_WONT %s: %d\n", TELCMD (i), will_wont_resp[i]);
	  else
	    printf ("resp WILL_WONT %d: %d\n", i, will_wont_resp[i]);
	  if (my_want_state_is_will (i))
	    {
	      if (TELOPT_OK (i))
		printf ("want WILL %s\n", TELOPT (i));
	      else if (TELCMD_OK (i))
		printf ("want WILL %s\n", TELCMD (i));
	      else
		printf ("want WILL %d\n", i);
	    }
	  else
	    {
	      if (TELOPT_OK (i))
		printf ("want WONT %s\n", TELOPT (i));
	      else if (TELCMD_OK (i))
		printf ("want WONT %s\n", TELCMD (i));
	      else
		printf ("want WONT %d\n", i);
	    }
	}
      else
	{
	  if (my_state_is_will (i))
	    {
	      if (TELOPT_OK (i))
		printf ("     WILL %s\n", TELOPT (i));
	      else if (TELCMD_OK (i))
		printf ("     WILL %s\n", TELCMD (i));
	      else
		printf ("     WILL %d\n", i);
	    }
	}
    }

}
Ejemplo n.º 9
0
/* input:  raw character
 * output: telnet command if c was handled, otherwise zero.
 */
unsigned int
telnet_handler(unsigned char c)
{
    static unsigned char iac_quote = 0; /* as byte to reduce memory */
    static unsigned char iac_opt_req = 0;

    static unsigned char iac_buf[TELNET_IAC_MAXLEN];
    static unsigned int  iac_buflen = 0;

    /* we have to quote all IACs. */
    if(c == IAC && !iac_quote) {
	iac_quote = 1;
	return NOP;
    }

#ifdef DETECT_CLIENT
    /* hash client telnet sequences */
    if(cuser.userid[0]==0) {
	if(iac_state == IAC_WAIT_SE) {
	    // skip suboption
	} else {
	    if(iac_quote)
		UpdateClientCode(IAC);
	    UpdateClientCode(c);
	}
    }
#endif

    /* a special case is the top level iac. otherwise, iac is just a quote. */
    if (iac_quote) {
	if(iac_state == IAC_NONE)
	    iac_state = IAC_COMMAND;
	if(iac_state == IAC_WAIT_SE && c == SE)
	    iac_state = IAC_PROCESS_OPT;
	iac_quote = 0;
    }

    /* now, let's process commands by state */
    switch(iac_state) {

	case IAC_NONE:
	    return 0;

	case IAC_COMMAND:
#if 0 // def DEBUG
	    {
		int cx = c; /* to make compiler happy */
		write(0, "-", 1);
		if(TELCMD_OK(cx))
		    write(0, TELCMD(c), strlen(TELCMD(c)));
		write(0, " ", 1);
	    }
#endif
	    iac_state = IAC_NONE; /* by default we restore state. */
	    switch(c) {
		case IAC:
		    // return 0;
		    // we don't want to allow IACs as input.
		    return 1;

		/* we don't want to process these. or maybe in future. */
		case BREAK:           /* break */
#ifdef DBG_OUTRPT
		    fakeEscape = !fakeEscape;
		    return NOP;
#endif

		case ABORT:           /* Abort process */
		case SUSP:            /* Suspend process */
		case AO:              /* abort output--but let prog finish */
		case IP:              /* interrupt process--permanently */
		case EOR:             /* end of record (transparent mode) */
		case DM:              /* data mark--for connect. cleaning */
		case xEOF:            /* End of file: EOF is already used... */
		    return NOP;

		case NOP:             /* nop */
		    return NOP;

		/* we should process these, but maybe in future. */
		case GA:              /* you may reverse the line */
		case EL:              /* erase the current line */
		case EC:              /* erase the current character */
		    return NOP;

		/* good */
		case AYT:             /* are you there */
		    {
			    const char *alive = "I'm still alive, loading: ";
			    char buf[STRLEN];

			    /* respond as fast as we can */
			    write(0, alive, strlen(alive));
//			    cpuload(buf);
			    buf[0] = '0';	// TODO: cpuload
			    write(0, buf, strlen(buf));
			    write(0, "\r\n", 2);
		    }
		    return NOP;

		case DONT:            /* you are not to use option */
		case DO:              /* please, you use option */
		case WONT:            /* I won't use option */
		case WILL:            /* I will use option */
		    iac_opt_req = c;
		    iac_state = IAC_WAIT_OPT;
		    return NOP;

		case SB:              /* interpret as subnegotiation */
		    iac_state = IAC_WAIT_SE;
		    iac_buflen = 0;
		    return NOP;

		case SE:              /* end sub negotiation */
		default:
		    return NOP;
	    }
	    return 1;

	case IAC_WAIT_OPT:
#if 0 // def DEBUG
	    write(0, "-", 1);
	    if(TELOPT_OK(c))
		write(0, TELOPT(c), strlen(TELOPT(c)));
	    write(0, " ", 1);
#endif
	    iac_state = IAC_NONE;
	    /*
	     * According to RFC, there're some tricky steps to prevent loop.
	     * However because we have a poor term which does not allow
	     * most abilities, let's be a strong boss here.
	     *
	     * Although my old imeplementation worked, it's even better to follow this:
	     * http://www.tcpipguide.com/free/t_TelnetOptionsandOptionNegotiation-3.htm
	     */
	    switch(c) {
		/* i-dont-care: i don't care about what client is.
		 * these should be clamed in init and
		 * client must follow me. */
		case TELOPT_TTYPE:	/* termtype or line. */
		case TELOPT_NAWS:       /* resize terminal */
		case TELOPT_SGA:	/* supress GA */
		case TELOPT_ECHO:       /* echo */
		case TELOPT_BINARY:	/* we are CJK. */
		    break;

		/* i-dont-agree: i don't understand/agree these.
		 * according to RFC, saying NO stopped further
		 * requests so there'll not be endless loop. */
		case TELOPT_RCP:         /* prepare to reconnect */
		default:
		    if (iac_opt_req == WILL || iac_opt_req == DO)
		    {
			/* unknown option, reply with won't */
			unsigned char cmd[3] = { IAC, DONT, 0 };
			if(iac_opt_req == DO) cmd[1] = WONT;
			cmd[2] = c;
			write(0, cmd, sizeof(cmd));
		    }
		    break;
	    }
	    return 1;

	case IAC_WAIT_SE:
	    iac_buf[iac_buflen++] = c;
	    /* no need to convert state because previous quoting will do. */

	    if(iac_buflen == TELNET_IAC_MAXLEN) {
		/* may be broken protocol?
		 * whether finished or not, break for safety
		 * or user may be frozen.
		 */
		iac_state = IAC_NONE;
		return 0;
	    }
	    return 1;

	case IAC_PROCESS_OPT:
	    iac_state = IAC_NONE;
#if 0 // def DEBUG
	    write(0, "-", 1);
	    if(TELOPT_OK(iac_buf[0]))
		write(0, TELOPT(iac_buf[0]), strlen(TELOPT(iac_buf[0])));
	    write(0, " ", 1);
#endif
	    switch(iac_buf[0]) {

		/* resize terminal */
		case TELOPT_NAWS:
		    {
			int w = (iac_buf[1] << 8) + (iac_buf[2]);
			int h = (iac_buf[3] << 8) + (iac_buf[4]);
			term_resize(w, h);
#ifdef DETECT_CLIENT
			if(cuser.userid[0]==0) {
			    UpdateClientCode(iac_buf[0]);
			    if(w==80 && h==24)
				UpdateClientCode(1);
			    else if(w==80)
				UpdateClientCode(2);
			    else if(h==24)
				UpdateClientCode(3);
			    else
				UpdateClientCode(4);
			    UpdateClientCode(IAC);
			    UpdateClientCode(SE);
			}
#endif
		    }
		    break;

		default:
#ifdef DETECT_CLIENT
		    if(cuser.userid[0]==0) {
			int i;
			for(i=0;i<iac_buflen;i++)
			    UpdateClientCode(iac_buf[i]);
			UpdateClientCode(IAC);
			UpdateClientCode(SE);
		    }
#endif
		    break;
	    }
	    return 1;
    }
    return 1; /* never reached */
}