/**************************************************************************** * apps/netutils/telnetc/telnetc.c * * Leveraged from libtelnet, https://github.com/seanmiddleditch/libtelnet. * Modified and re-released under the BSD license: * * Copyright (C) 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * The original authors of libtelnet are listed below. Per their licesne, * "The author or authors of this code dedicate any and all copyright * interest in this code to the public domain. We make this dedication for * the benefit of the public at large and to the detriment of our heirs and * successors. We intend this dedication to be an overt act of * relinquishment in perpetuity of all present and future rights to this * code under copyright law." * * Author: Sean Middleditch * (Also listed in the AUTHORS file are Jack Kelly * and Katherine Flavel ) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /* libtelnet - TELNET protocol handling library * * SUMMARY: * * libtelnet is a library for handling the TELNET protocol. It includes * routines for parsing incoming data from a remote peer as well as formatting * data to send to the remote peer. * * libtelnet uses a callback-oriented API, allowing application-specific * handling of various events. The callback system is also used for buffering * outgoing protocol data, allowing the application to maintain control over * the actual socket connection. * * Features supported include the full TELNET protocol, Q-method option * negotiation, ZMP, MCCP2, MSSP, and NEW-ENVIRON. * * CONFORMS TO: * * RFC854 - http://www.faqs.org/rfcs/rfc854.html * RFC855 - http://www.faqs.org/rfcs/rfc855.html * RFC1091 - http://www.faqs.org/rfcs/rfc1091.html * RFC1143 - http://www.faqs.org/rfcs/rfc1143.html * RFC1408 - http://www.faqs.org/rfcs/rfc1408.html * RFC1572 - http://www.faqs.org/rfcs/rfc1572.html * * LICENSE: * * The author or authors of this code dedicate any and all copyright interest * in this code to the public domain. We make this dedication for the benefit * of the public at large and to the detriment of our heirs and successors. We * intend this dedication to be an overt act of relinquishment in perpetuity of * all present and future rights to this code under copyright law. * * Author: Sean Middleditch */ #ifndef __APPS_INCLUDE_NETUTILS_TELNETC_H #define __APPS_INCLUDE_NETUTILS_TELNETC_H 1 /**************************************************************************** * Included Files ****************************************************************************/ #include /* C++ support */ #if defined(__cplusplus) extern "C" { #endif /**************************************************************************** * Pre-proecessor Definitions ****************************************************************************/ /* Telnet commands and special values. */ #define TELNET_IAC 255 #define TELNET_DONT 254 #define TELNET_DO 253 #define TELNET_WONT 252 #define TELNET_WILL 251 #define TELNET_SB 250 #define TELNET_GA 249 #define TELNET_EL 248 #define TELNET_EC 247 #define TELNET_AYT 246 #define TELNET_AO 245 #define TELNET_IP 244 #define TELNET_BREAK 243 #define TELNET_DM 242 #define TELNET_NOP 241 #define TELNET_SE 240 #define TELNET_EOR 239 #define TELNET_ABORT 238 #define TELNET_SUSP 237 #define TELNET_EOF 236 /* Telnet options. */ #define TELNET_TELOPT_BINARY 0 #define TELNET_TELOPT_ECHO 1 #define TELNET_TELOPT_RCP 2 #define TELNET_TELOPT_SGA 3 #define TELNET_TELOPT_NAMS 4 #define TELNET_TELOPT_STATUS 5 #define TELNET_TELOPT_TM 6 #define TELNET_TELOPT_RCTE 7 #define TELNET_TELOPT_NAOL 8 #define TELNET_TELOPT_NAOP 9 #define TELNET_TELOPT_NAOCRD 10 #define TELNET_TELOPT_NAOHTS 11 #define TELNET_TELOPT_NAOHTD 12 #define TELNET_TELOPT_NAOFFD 13 #define TELNET_TELOPT_NAOVTS 14 #define TELNET_TELOPT_NAOVTD 15 #define TELNET_TELOPT_NAOLFD 16 #define TELNET_TELOPT_XASCII 17 #define TELNET_TELOPT_LOGOUT 18 #define TELNET_TELOPT_BM 19 #define TELNET_TELOPT_DET 20 #define TELNET_TELOPT_SUPDUP 21 #define TELNET_TELOPT_SUPDUPOUTPUT 22 #define TELNET_TELOPT_SNDLOC 23 #define TELNET_TELOPT_TTYPE 24 #define TELNET_TELOPT_EOR 25 #define TELNET_TELOPT_TUID 26 #define TELNET_TELOPT_OUTMRK 27 #define TELNET_TELOPT_TTYLOC 28 #define TELNET_TELOPT_3270REGIME 29 #define TELNET_TELOPT_X3PAD 30 #define TELNET_TELOPT_NAWS 31 #define TELNET_TELOPT_TSPEED 32 #define TELNET_TELOPT_LFLOW 33 #define TELNET_TELOPT_LINEMODE 34 #define TELNET_TELOPT_XDISPLOC 35 #define TELNET_TELOPT_ENVIRON 36 #define TELNET_TELOPT_AUTHENTICATION 37 #define TELNET_TELOPT_ENCRYPT 38 #define TELNET_TELOPT_NEW_ENVIRON 39 #define TELNET_TELOPT_MSSP 70 #define TELNET_TELOPT_COMPRESS 85 #define TELNET_TELOPT_COMPRESS2 86 #define TELNET_TELOPT_ZMP 93 #define TELNET_TELOPT_EXOPL 255 #define TELNET_TELOPT_MCCP2 86 /* TERMINAL-TYPE codes. */ #define TELNET_TTYPE_IS 0 #define TELNET_TTYPE_SEND 1 /* NEW-ENVIRON/ENVIRON codes. */ #define TELNET_ENVIRON_IS 0 #define TELNET_ENVIRON_SEND 1 #define TELNET_ENVIRON_INFO 2 #define TELNET_ENVIRON_VAR 0 #define TELNET_ENVIRON_VALUE 1 #define TELNET_ENVIRON_ESC 2 #define TELNET_ENVIRON_USERVAR 3 /* MSSP codes. */ #define TELNET_MSSP_VAR 1 #define TELNET_MSSP_VAL 2 /* Telnet state tracker flags. */ #define TELNET_FLAG_PROXY (1 << 0) #define TELNET_PFLAG_DEFLATE (1 << 7) /**************************************************************************** * Public Types ****************************************************************************/ /* Error codes */ enum telnet_error_u { TELNET_EOK = 0, /* No error */ TELNET_EBADVAL, /* Invalid parameter, or API misuse */ TELNET_ENOMEM, /* Memory allocation failure */ TELNET_EOVERFLOW, /* Data exceeds buffer size */ TELNET_EPROTOCOL, /* Invalid sequence of special bytes */ TELNET_ECOMPRESS /* Error handling compressed streams */ }; /* Event codes */ enum telnet_event_type_e { TELNET_EV_DATA = 0, /* Raw text data has been received */ TELNET_EV_SEND, /* Data needs to be sent to the peer */ TELNET_EV_IAC, /* Generic IAC code received */ TELNET_EV_WILL, /* WILL option negotiation received */ TELNET_EV_WONT, /* WONT option neogitation received */ TELNET_EV_DO, /* DO option negotiation received */ TELNET_EV_DONT, /* DONT option negotiation received */ TELNET_EV_SUBNEGOTIATION, /* Sub-negotiation data received */ TELNET_EV_COMPRESS, /* Compression has been enabled */ TELNET_EV_ZMP, /* ZMP command has been received */ TELNET_EV_TTYPE, /* TTYPE command has been received */ TELNET_EV_ENVIRON, /* ENVIRON command has been received */ TELNET_EV_MSSP, /* MSSP command has been received */ TELNET_EV_WARNING, /* Recoverable error has occured */ TELNET_EV_ERROR /* Non-recoverable error has occured */ }; /* Environ/MSSP command information */ struct telnet_environ_s { unsigned char type; /* either TELNET_ENVIRON_VAR or * TELNET_ENVIRON_USERVAR */ char *var; /* Name of the variable being set */ char *value; /* value of variable being set; empty string * if no value */ }; /* State tracker -- private data structure */ struct telnet_s; /* Forward reference */ /* Event information */ union telnet_event_u { /* Event type The type field will determine which of the other * event structure fields have been filled in. For instance, if the * event type is TELNET_EV_ZMP, then the zmp event field (and ONLY the * zmp event field) will be filled in. */ enum telnet_event_type_e type; /* Data event: for DATA and SEND events */ struct { enum telnet_event_type_e _type; /* Alias for type */ const char *buffer; /* Byte buffer */ size_t size; /* Number of bytes in buffer */ } data; /* WARNING and ERROR events */ struct { enum telnet_event_type_e _type; /* Alias for type */ const char *file; /* File the error occured in */ const char *func; /* Function the error occured in */ const char *msg; /* Error message string */ int line; /* Line of file error occured on */ enum telnet_error_u errcode; /* Error code */ } error; /* Command event: for IAC */ struct { enum telnet_event_type_e _type; /* Alias for type */ unsigned char cmd; /* Telnet command received */ } iac; /* Negotiation event: WILL, WONT, DO, DONT */ struct { enum telnet_event_type_e _type; /* Alias for type */ unsigned char telopt; /* Option being negotiated */ } neg; /* Subnegotiation event */ struct { enum telnet_event_type_e _type; /* Alias for type */ const char *buffer; /* Data of sub-negotiation */ size_t size; /* Number of bytes in buffer */ unsigned char telopt; /* Option code for negotiation */ } sub; /* ZMP event */ struct { enum telnet_event_type_e _type; /* Alias for type */ const char **argv; /* Array of argument string */ size_t argc; /* Number of elements in argv */ } zmp; /* TTYPE event */ struct { enum telnet_event_type_e _type; /* Alias for type */ unsigned char cmd; /* TELNET_TTYPE_IS or TELNET_TTYPE_SEND */ const char *name; /* Terminal type name (IS only) */ } ttype; /* COMPRESS event */ struct { enum telnet_event_type_e _type; /* Alias for type */ unsigned char state; /* 1 if compression is enabled, 0 if * disabled */ } compress; /* ENVIRON/NEW-ENVIRON event */ struct { enum telnet_event_type_e _type; /* Alias for type */ const struct telnet_environ_s *values; /* Array of variable values */ size_t size; /* Number of elements in values */ unsigned char cmd; /* SEND, IS, or INFO */ } envevent; /* MSSP event */ struct { enum telnet_event_type_e _type; /* Alias for type */ const struct telnet_environ_s *values; /* Array of variable values */ size_t size; /* Number of elements in values */ } mssp; }; /* Name: telnet_event_handler_t * * Description: * This is the type of function that must be passed to * telnet_init() when creating a new telnet object. The * function will be invoked once for every event generated * by the libtelnet protocol parser. * * Input Parameters: * telnet The telnet object that generated the event * event Event structure with details about the event * user_data User-supplied pointer */ typedef void (*telnet_event_handler_t)(struct telnet_s *telnet, union telnet_event_u *event, void *user_data); /* telopt support table element; use telopt of -1 for end marker */ struct telnet_telopt_s { short telopt; /* One of the TELOPT codes or -1 */ unsigned char us; /* TELNET_WILL or TELNET_WONT */ unsigned char him; /* TELNET_DO or TELNET_DONT */ }; /**************************************************************************** * Public Function Prototypes ****************************************************************************/ /**************************************************************************** * Name: telnet_init * * Description: * Initialize a telnet state tracker. * * This function initializes a new state tracker, which is used for all * other libtelnet functions. Each connection must have its own * telnet state tracker object. * * Input Parameters: * telopts Table of TELNET options the application supports. * eh Event handler function called for every event. * flags 0 or TELNET_FLAG_PROXY. * user_data Optional data pointer that will be passsed to eh. * * Returned Value: * Telent state tracker object. * ****************************************************************************/ struct telnet_s *telnet_init(const struct telnet_telopt_s *telopts, telnet_event_handler_t eh, unsigned char flags, void *user_data); /**************************************************************************** * Name: telnet_free * * Description: * Free up any memory allocated by a state tracker. * * This function must be called when a telnet state tracker is no * longer needed (such as after the connection has been closed) to * release any memory resources used by the state tracker. * * Input Parameters: * telnet Telnet state tracker object. * ****************************************************************************/ void telnet_free(struct telnet_s *telnet); /**************************************************************************** * Name: telnet_recv * * Description: * Push a byte buffer into the state tracker. * * Passes one or more bytes to the telnet state tracker for * protocol parsing. The byte buffer is most often going to be * the buffer that recv() was called for while handling the * connection. * * Input Parameters: * telnet Telnet state tracker object. * buffer Pointer to byte buffer. * size Number of bytes pointed to by buffer. * ****************************************************************************/ void telnet_recv(struct telnet_s *telnet, const char *buffer, size_t size); /**************************************************************************** * Name: telnet_iac * * Description: * Send a telnet command. * * Input Parameters: * telnet Telnet state tracker object. * cmd Command to send. * ****************************************************************************/ void telnet_iac(struct telnet_s *telnet, unsigned char cmd); /**************************************************************************** * Name: telnet_negotiate * * Description: * Send negotiation command. * * Internally, libtelnet uses RFC1143 option negotiation rules. * The negotiation commands sent with this function may be ignored * if they are determined to be redundant. * * Input Parameters: * telnet Telnet state tracker object. * cmd TELNET_WILL, TELNET_WONT, TELNET_DO, or TELNET_DONT. * opt One of the TELNET_TELOPT_* values. * ****************************************************************************/ void telnet_negotiate(struct telnet_s *telnet, unsigned char cmd, unsigned char opt); /**************************************************************************** * Name: telnet_send * * Description: * Send non-command data (escapes IAC bytes). * * Input Parameters: * telnet Telnet state tracker object. * buffer Buffer of bytes to send. * size Number of bytes to send. * ****************************************************************************/ void telnet_send(struct telnet_s *telnet, const char *buffer, size_t size); /**************************************************************************** * Name: telnet_begin_sb * * Description: * Begin a sub-negotiation command. * * Sends IAC SB followed by the telopt code. All following data sent * will be part of the sub-negotiation, until telnet_finish_sb() is * called. * * Input Parameters: * telnet Telnet state tracker object. * telopt One of the TELNET_TELOPT_* values. * ****************************************************************************/ void telnet_begin_sb(struct telnet_s *telnet, unsigned char telopt); /**************************************************************************** * Name: telnet_finish_sb * * Description: * Finish a sub-negotiation command. * * This must be called after a call to telnet_begin_sb() to finish a * sub-negotiation command. * * Input Parameters: * telnet Telnet state tracker object. * ****************************************************************************/ #define telnet_finish_sb(telnet) telnet_iac((telnet), TELNET_SE) /**************************************************************************** * Name: telnet_subnegotiation * * Description: * Send a complete subnegotiation buffer. * * Equivalent to: * telnet_begin_sb(telnet, telopt); * telnet_send(telnet, buffer, size); * telnet_finish_sb(telnet); * * Input Parameters: * telnet Telnet state tracker format. * telopt One of the TELNET_TELOPT_* values. * buffer Byte buffer for sub-negotiation data. * size Number of bytes to use for sub-negotiation data. * ****************************************************************************/ void telnet_subnegotiation(struct telnet_s *telnet, unsigned char telopt, const char *buffer, size_t size); /**************************************************************************** * Name: telnet_begin_compress2 * * Description: * Begin sending compressed data. * * This function will begein sending data using the COMPRESS2 option, * which enables the use of zlib to compress data sent to the client. * The client must offer support for COMPRESS2 with option negotiation, * and zlib support must be compiled into libtelnet. * * Only the server may call this command. * * Input Parameters: * telnet Telnet state tracker object. * ****************************************************************************/ void telnet_begin_compress2(struct telnet_s *telnet); /**************************************************************************** * Name: telnet_printf * * Description: * Send formatted data. * * This function is a wrapper around telnet_send(). It allows using * printf-style formatting. * * Additionally, this function will translate \\r to the CR NUL construct * and \\n with CR LF, as well as automatically escaping IAC bytes like * telnet_send(). * * Input Parameters: * telnet Telnet state tracker object. * fmt Format string. * * Returned Value: * Number of bytes sent. * ****************************************************************************/ int telnet_printf(struct telnet_s *telnet, const char *fmt, ...); /**************************************************************************** * Name: telnet_vprintf * * Description: * Send formatted data with \r and \n translation in addition to IAC IAC * * See telnet_printf(). * ****************************************************************************/ int telnet_vprintf(struct telnet_s *telnet, const char *fmt, va_list va); /**************************************************************************** * Name: telnet_raw_printf * * Description: * Send formatted data (no newline escaping). * * This behaves identically to telnet_printf(), except that the \\r and \\n * characters are not translated. The IAC byte is still escaped as normal * with telnet_send(). * * Input Parameters: * telnet Telnet state tracker object. * fmt Format string. * * Returned Value: * Number of bytes sent. * ****************************************************************************/ int telnet_raw_printf(struct telnet_s *telnet, const char *fmt, ...); /**************************************************************************** * Name: telnet_raw_vprintf * * Description: * Send formatted data (no newline escaping). * * See telnet_raw_printf(). * ****************************************************************************/ int telnet_raw_vprintf(struct telnet_s *telnet, const char *fmt, va_list va); /**************************************************************************** * Name: telnet_begin_newenviron * * Description: * Begin a new set of NEW-ENVIRON values to request or send. * * This function will begin the sub-negotiation block for sending or * requesting NEW-ENVIRON values. * * The telnet_finish_newenviron() macro must be called after this * function to terminate the NEW-ENVIRON command. * * Input Parameters: * telnet Telnet state tracker object. * type One of TELNET_ENVIRON_SEND, TELNET_ENVIRON_IS, or * TELNET_ENVIRON_INFO. * ****************************************************************************/ void telnet_begin_newenviron(struct telnet_s *telnet, unsigned char type); /**************************************************************************** * Name: telnet_newenviron_value * * Description: * Send a NEW-ENVIRON variable name or value. * * This can only be called between calls to telnet_begin_newenviron() and * telnet_finish_newenviron(). * * Input Parameters: * telnet Telnet state tracker object. * type One of TELNET_ENVIRON_VAR, TELNET_ENVIRON_USERVAR, or * TELNET_ENVIRON_VALUE. * string Variable name or value. * ****************************************************************************/ void telnet_newenviron_value(struct telnet_s *telnet, unsigned char type, const char *string); /**************************************************************************** * Name: telnet_finish_newenviron * * Description: * Finish a NEW-ENVIRON command. * * This must be called after a call to telnet_begin_newenviron() to finish a * NEW-ENVIRON variable list. * * telnet Telnet state tracker object. * ****************************************************************************/ #define telnet_finish_newenviron(telnet) telnet_finish_sb((telnet)) /**************************************************************************** * Name: telnet_ttype_send * * Description: * Send the TERMINAL-TYPE SEND command. * * Sends the sequence IAC TERMINAL-TYPE SEND. * * telnet Telnet state tracker object. * ****************************************************************************/ void telnet_ttype_send(struct telnet_s * telnet); /**************************************************************************** * Name: telnet_ttype_is * * Description: * Send the TERMINAL-TYPE IS command. * * Sends the sequence IAC TERMINAL-TYPE IS "string". * * According to the RFC, the recipient of a TERMINAL-TYPE SEND shall * send the next possible terminal-type the client supports. Upon sending * the type, the client should switch modes to begin acting as the terminal * type is just sent. * * The server may continue sending TERMINAL-TYPE IS until it receives a * terminal type is understands. To indicate to the server that it has * reached the end of the available optoins, the client must send the last * terminal type a second time. When the server receives the same terminal * type twice in a row, it knows it has seen all available terminal types. * * After the last terminal type is sent, if the client receives another * TERMINAL-TYPE SEND command, it must begin enumerating the available * terminal types from the very beginning. This allows the server to * scan the available types for a preferred terminal type and, if none * is found, to then ask the client to switch to an acceptable * alternative. * * Note that if the client only supports a single terminal type, then * simply sending that one type in response to every SEND will satisfy * the behavior requirements. * * Input Parameters: * telnet Telnet state tracker object. * ttype Name of the terminal-type being sent. * ****************************************************************************/ void telnet_ttype_is(struct telnet_s * telnet, const char *ttype); /**************************************************************************** * Name: telnet_send_zmp * * Description: * Send a ZMP command. * * Input Parameters: * telnet Telnet state tracker object. * argc Number of ZMP commands being sent. * argv Array of argument strings. * ****************************************************************************/ void telnet_send_zmp(struct telnet_s * telnet, size_t argc, const char **argv); /**************************************************************************** * Name: telnet_send_zmpv * * Description: * Send a ZMP command. * * Arguments are listed out in var-args style. After the last argument, a * NULL pointer must be passed in as a sentinel value. * * Input Parameters: * telnet Telnet state tracker object. * ****************************************************************************/ void telnet_send_zmpv(struct telnet_s * telnet, ...); /**************************************************************************** * Name: telnet_send_vzmpv * * Description: * Send a ZMP command. * * See telnet_send_zmpv(). * ****************************************************************************/ void telnet_send_vzmpv(struct telnet_s * telnet, va_list va); /**************************************************************************** * Name: telnet_begin_zmp * * Description: * Begin sending a ZMP command * * Input Parameters: * telnet Telnet state tracker object. * cmd The first argument (command name) for the ZMP command. * ****************************************************************************/ void telnet_begin_zmp(struct telnet_s * telnet, const char *cmd); /**************************************************************************** * Name: telnet_zmp_arg * * Description: * Send a ZMP command argument. * * Input Parameters: * telnet Telnet state tracker object. * arg Telnet argument string. * ****************************************************************************/ void telnet_zmp_arg(struct telnet_s * telnet, const char *arg); /**************************************************************************** * Name: telnet_finish_zmp * * Description: * Finish a ZMP command. * * This must be called after a call to telnet_begin_zmp() to finish a * ZMP argument list. * * Input Parameters: * telnet Telnet state tracker object. * ****************************************************************************/ #define telnet_finish_zmp(telnet) telnet_finish_sb((telnet)) #if defined(__cplusplus) } #endif #endif /* __APPS_INCLUDE_NETUTILS_TELNETC_H */