1 /* 2 * vim: filetype=c:tabstop=4:ai:expandtab 3 * SPDX-License-Identifier: CC-PDDC or MIT-0 4 * SPDX-FileCopyrightText: Public domain or The DPS8M Development Team 5 * scspell-id: 8a194784-f62f-11ec-85b5-80ee73e9b8e7 6 * 7 * --------------------------------------------------------------------------- 8 * 9 * libTELNET - TELNET protocol handling library 10 * 11 * SUMMARY: 12 * 13 * libTELNET is a library for handling the TELNET protocol. It includes 14 * routines for parsing incoming data from a remote peer as well as 15 * formatting data to send to the remote peer. 16 * 17 * libTELNET uses a callback-oriented API, allowing application-specific 18 * handling of various events. The callback system is also used for 19 * buffering outgoing protocol data, allowing the application to maintain 20 * control over the actual socket connection. 21 * 22 * Features supported include the full TELNET protocol, Q-method option 23 * negotiation, and NEW-ENVIRON. 24 * 25 * --------------------------------------------------------------------------- 26 * 27 * CONFORMS TO: 28 * 29 * RFC-854 - https://www.faqs.org/rfcs/rfc854.html 30 * RFC-855 - https://www.faqs.org/rfcs/rfc855.html 31 * RFC-1091 - https://www.faqs.org/rfcs/rfc1091.html 32 * RFC-1143 - https://www.faqs.org/rfcs/rfc1143.html 33 * RFC-1408 - https://www.faqs.org/rfcs/rfc1408.html 34 * RFC-1572 - https://www.faqs.org/rfcs/rfc1572.html 35 * 36 * --------------------------------------------------------------------------- 37 * 38 * LICENSE: 39 * 40 * The author or authors of this code dedicate any and all copyright 41 * interest in this code to the public domain. We make this dedication 42 * for the benefit of the public at large and to the detriment of our 43 * heirs and successors. We intend this dedication to be an overt act 44 * of relinquishment in perpetuity of all present and future rights to 45 * this code under copyright law. 46 * 47 * --------------------------------------------------------------------------- 48 * 49 * Sean Middleditch <sean@sourcemud.org> 50 * 51 * --------------------------------------------------------------------------- 52 */ 53 54 /* 55 * The person or persons who have associated work with this document 56 * (the "Dedicator" or "Certifier") hereby either (a) certifies that, 57 * to the best of his knowledge, the work of authorship identified 58 * is in the public domain of the country from which the work is 59 * published, or (b) hereby dedicates whatever copyright the dedicators 60 * holds in the work of authorship identified below (the "Work") to the 61 * public domain. A certifier, moreover, dedicates any copyright 62 * interest he may have in the associated work, and for these purposes, 63 * is described as a "dedicator" below. 64 * 65 * A certifier has taken reasonable steps to verify the copyright 66 * status of this work. Certifier recognizes that his good faith 67 * efforts may not shield him from liability if in fact the work 68 * certified is not in the public domain. 69 * 70 * Dedicator makes this dedication for the benefit of the public at 71 * large and to the detriment of the Dedicator's heirs and successors. 72 * Dedicator intends this dedication to be an overt act of 73 * relinquishment in perpetuity of all present and future rights under 74 * copyright law, whether vested or contingent, in the Work. Dedicator 75 * understands that such relinquishment of all rights includes the 76 * relinquishment of all rights to enforce (by lawsuit or otherwise) 77 * those copyrights in the Work. 78 * 79 * Dedicator recognizes that, once placed in the public domain, the 80 * Work may be freely reproduced, distributed, transmitted, used, 81 * modified, built upon, or otherwise exploited by anyone for any 82 * purpose, commercial or non-commercial, and in any way, including by 83 * methods that have not yet been invented or conceived. 84 */ 85 86 #if !defined(LIBTELNET_INCLUDE) 87 # define LIBTELNET_INCLUDE 1 88 89 /* local definitions */ 90 # include "dps8.h" 91 92 /* standard C headers necessary for the libTELNET API */ 93 # include <stdarg.h> 94 # include <stddef.h> 95 96 /* printf type checking feature in GCC and some other compilers */ 97 # if defined(__GNUC__) && !defined(USING_DPSPRINTF) 98 # define TELNET_GNU_PRINTF(f,a) __attribute__((format(printf, f, a))) /* internal helper */ 99 # define TELNET_GNU_SENTINEL __attribute__((sentinel)) /* internal helper */ 100 # else 101 # define TELNET_GNU_PRINTF(f,a) /* internal helper */ 102 # define TELNET_GNU_SENTINEL /* internal helper */ 103 # endif 104 105 /* Disable environ macro for Visual C++ 2015. */ 106 # undef environ 107 108 /* Telnet state tracker object type. */ 109 typedef struct telnet_t telnet_t; 110 111 /* Telnet event object type. */ 112 typedef union telnet_event_t telnet_event_t; 113 114 /* Telnet option table element type. */ 115 typedef struct telnet_telopt_t telnet_telopt_t; 116 117 /* Telnet commands and special values. */ 118 # define TELNET_IAC 255 119 # define TELNET_DONT 254 120 # define TELNET_DO 253 121 # define TELNET_WONT 252 122 # define TELNET_WILL 251 123 # define TELNET_SB 250 124 # define TELNET_GA 249 125 # define TELNET_EL 248 126 # define TELNET_EC 247 127 # define TELNET_AYT 246 128 # define TELNET_AO 245 129 # define TELNET_IP 244 130 # define TELNET_BREAK 243 131 # define TELNET_DM 242 132 # define TELNET_NOP 241 133 # define TELNET_SE 240 134 # define TELNET_EOR 239 135 # define TELNET_ABORT 238 136 # define TELNET_SUSP 237 137 # define TELNET_EOF 236 138 139 /* Telnet option values. */ 140 # define TELNET_TELOPT_BINARY 0 141 # define TELNET_TELOPT_ECHO 1 142 # define TELNET_TELOPT_RCP 2 143 # define TELNET_TELOPT_SGA 3 144 # define TELNET_TELOPT_NAMS 4 145 # define TELNET_TELOPT_STATUS 5 146 # define TELNET_TELOPT_TM 6 147 # define TELNET_TELOPT_RCTE 7 148 # define TELNET_TELOPT_NAOL 8 149 # define TELNET_TELOPT_NAOP 9 150 # define TELNET_TELOPT_NAOCRD 10 151 # define TELNET_TELOPT_NAOHTS 11 152 # define TELNET_TELOPT_NAOHTD 12 153 # define TELNET_TELOPT_NAOFFD 13 154 # define TELNET_TELOPT_NAOVTS 14 155 # define TELNET_TELOPT_NAOVTD 15 156 # define TELNET_TELOPT_NAOLFD 16 157 # define TELNET_TELOPT_XASCII 17 158 # define TELNET_TELOPT_LOGOUT 18 159 # define TELNET_TELOPT_BM 19 160 # define TELNET_TELOPT_DET 20 161 # define TELNET_TELOPT_SUPDUP 21 162 # define TELNET_TELOPT_SUPDUPOUTPUT 22 163 # define TELNET_TELOPT_SNDLOC 23 164 # define TELNET_TELOPT_TTYPE 24 165 # define TELNET_TELOPT_EOR 25 166 # define TELNET_TELOPT_TUID 26 167 # define TELNET_TELOPT_OUTMRK 27 168 # define TELNET_TELOPT_TTYLOC 28 169 # define TELNET_TELOPT_3270REGIME 29 170 # define TELNET_TELOPT_X3PAD 30 171 # define TELNET_TELOPT_NAWS 31 172 # define TELNET_TELOPT_TSPEED 32 173 # define TELNET_TELOPT_LFLOW 33 174 # define TELNET_TELOPT_LINEMODE 34 175 # define TELNET_TELOPT_XDISPLOC 35 176 # define TELNET_TELOPT_ENVIRON 36 177 # define TELNET_TELOPT_AUTHENTICATION 37 178 # define TELNET_TELOPT_ENCRYPT 38 179 # define TELNET_TELOPT_NEW_ENVIRON 39 180 # define TELNET_TELOPT_EXOPL 255 181 182 /* Protocol codes for TERMINAL-TYPE commands. */ 183 # define TELNET_TTYPE_IS 0 184 # define TELNET_TTYPE_SEND 1 185 186 /* Protocol codes for NEW-ENVIRON/ENVIRON commands. */ 187 # define TELNET_ENVIRON_IS 0 188 # define TELNET_ENVIRON_SEND 1 189 # define TELNET_ENVIRON_INFO 2 190 # define TELNET_ENVIRON_VAR 0 191 # define TELNET_ENVIRON_VALUE 1 192 # define TELNET_ENVIRON_ESC 2 193 # define TELNET_ENVIRON_USERVAR 3 194 195 /* Telnet state tracker flags. */ 196 197 /* Control behavior of telnet state tracker. */ 198 # define TELNET_FLAG_PROXY (1<<0) 199 # define TELNET_FLAG_NVT_EOL (1<<1) 200 201 /* Internal-only bits in option flags */ 202 # define TELNET_FLAG_TRANSMIT_BINARY (1<<5) 203 # define TELNET_FLAG_RECEIVE_BINARY (1<<6) 204 # define TELNET_PFLAG_DEFLATE (1<<7) 205 206 /* 207 * error codes 208 */ 209 enum telnet_error_t { 210 TELNET_EOK = 0, /* no error */ 211 TELNET_EBADVAL, /* invalid parameter, or API misuse */ 212 TELNET_ENOMEM, /* memory allocation failure */ 213 TELNET_EOVERFLOW, /* data exceeds buffer size */ 214 TELNET_EPROTOCOL, /* invalid sequence of special bytes */ 215 }; 216 typedef enum telnet_error_t telnet_error_t; /* Error code type. */ 217 218 /* 219 * event codes 220 */ 221 enum telnet_event_type_t { 222 TELNET_EV_DATA = 0, /* raw text data has been received */ 223 TELNET_EV_SEND, /* data needs to be sent to the peer */ 224 TELNET_EV_IAC, /* generic IAC code received */ 225 TELNET_EV_WILL, /* WILL option negotiation received */ 226 TELNET_EV_WONT, /* WONT option negotiation received */ 227 TELNET_EV_DO, /* DO option negotiation received */ 228 TELNET_EV_DONT, /* DONT option negotiation received */ 229 TELNET_EV_SUBNEGOTIATION, /* sub-negotiation data received */ 230 TELNET_EV_TTYPE, /* TTYPE command has been received */ 231 TELNET_EV_ENVIRON, /* ENVIRON command has been received */ 232 TELNET_EV_WARNING, /* recoverable error has occurred */ 233 TELNET_EV_ERROR /* non-recoverable error has occurred */ 234 }; 235 typedef enum telnet_event_type_t telnet_event_type_t; /* Telnet event type */ 236 237 /* 238 * environ command information 239 */ 240 struct telnet_environ_t { 241 unsigned char type; /* either TELNET_ENVIRON_VAR or TELNET_ENVIRON_USERVAR */ 242 char *var; /* name of the variable being set */ 243 char *value; /* value of variable being set; empty string if no value */ 244 }; 245 246 /* 247 * event information 248 */ 249 union telnet_event_t { 250 /* 251 * Event type 252 * 253 * The type field determines which event structure fields have been filled in. 254 */ 255 enum telnet_event_type_t type; 256 257 /* 258 * Data event: for DATA and SEND events 259 */ 260 struct data_t { 261 enum telnet_event_type_t _type; /* alias for type */ 262 const char *buffer; /* byte buffer */ 263 size_t size; /* number of bytes in buffer */ 264 } data; 265 266 /* 267 * WARNING and ERROR events 268 */ 269 struct error_t { 270 enum telnet_event_type_t _type; /* alias for type */ 271 const char *file; /* file the error occurred in */ 272 const char *func; /* function the error occurred in */ 273 const char *msg; /* error message string */ 274 int line; /* line of file error occurred on */ 275 telnet_error_t errcode; /* error code */ 276 } error; 277 278 /* 279 * command event: for IAC 280 */ 281 struct iac_t { 282 enum telnet_event_type_t _type; /* alias for type */ 283 unsigned char cmd; /* telnet command received */ 284 } iac; 285 286 /* 287 * negotiation event: WILL, WONT, DO, DONT 288 */ 289 struct negotiate_t { 290 enum telnet_event_type_t _type; /* alias for type */ 291 unsigned char telopt; /* option being negotiated */ 292 } neg; 293 294 /* 295 * subnegotiation event 296 */ 297 struct subnegotiate_t { 298 enum telnet_event_type_t _type; /* alias for type */ 299 const char *buffer; /* data of sub-negotiation */ 300 size_t size; /* number of bytes in buffer */ 301 unsigned char telopt; /* option code for negotiation */ 302 } sub; 303 304 /* 305 * TTYPE event 306 */ 307 struct ttype_t { 308 enum telnet_event_type_t _type; /* alias for type */ 309 unsigned char cmd; /* TELNET_TTYPE_IS or TELNET_TTYPE_SEND */ 310 const char* name; /* terminal type name (IS only) */ 311 } ttype; 312 313 /* 314 * ENVIRON/NEW-ENVIRON event 315 */ 316 struct environ_t { 317 enum telnet_event_type_t _type; /* alias for type */ 318 const struct telnet_environ_t *values; /* array of variable values */ 319 size_t size; /* number of elements in values */ 320 unsigned char cmd; /* SEND, IS, or INFO */ 321 } environ; 322 }; 323 324 /* 325 * event handler 326 * 327 * This is the type of function that must be passed to 328 * telnet_init() when creating a new telnet object. The 329 * function will be invoked once for every event generated 330 * by the libTELNET protocol parser. 331 * 332 * param telnet The telnet object that generated the event 333 * param event Event structure with details about the event 334 * param user_data User-supplied pointer 335 */ 336 typedef void (*telnet_event_handler_t)(telnet_t *telnet, 337 telnet_event_t *event, void *user_data); 338 339 /* 340 * telopt support table element; use telopt of -1 for end marker 341 */ 342 struct telnet_telopt_t { 343 short telopt; /* one of the TELOPT codes or -1 */ 344 unsigned char us; /* TELNET_WILL or TELNET_WONT */ 345 unsigned char him; /* TELNET_DO or TELNET_DONT */ 346 }; 347 348 /* 349 * state tracker -- private data structure 350 */ 351 struct telnet_t; 352 353 /* 354 * Initialize a telnet state tracker. 355 * 356 * This function initializes a new state tracker, which is used for all 357 * other libTELNET functions. Each connection must have its own 358 * telnet state tracker object. 359 * 360 * param telopts Table of TELNET options the application supports. 361 * param eh Event handler function called for every event. 362 * param flags 0 or TELNET_FLAG_PROXY. 363 * param user_data Optional data pointer that will be passed to eh. 364 * return Telnet state tracker object. 365 */ 366 extern telnet_t* telnet_init(const telnet_telopt_t *telopts, 367 telnet_event_handler_t eh, unsigned char flags, 368 void *user_data); 369 370 /* 371 * Free up any memory allocated by a state tracker. 372 * 373 * This function must be called when a telnet state tracker is no 374 * longer needed (such as after the connection has been closed) to 375 * release any memory resources used by the state tracker. 376 * 377 * param telnet Telnet state tracker object. 378 */ 379 extern void telnet_free(telnet_t *telnet); 380 381 /* 382 * Push a byte buffer into the state tracker. 383 * 384 * Passes one or more bytes to the telnet state tracker for 385 * protocol parsing. The byte buffer is most often going to be 386 * the buffer that recv() was called for while handling the 387 * connection. 388 * 389 * param telnet Telnet state tracker object. 390 * param buffer Pointer to byte buffer. 391 * param size Number of bytes pointed to by buffer. 392 */ 393 extern void telnet_recv(telnet_t *telnet, const char *buffer, 394 size_t size); 395 396 /* 397 * Send a telnet command. 398 * 399 * param telnet Telnet state tracker object. 400 * param cmd Command to send. 401 */ 402 extern void telnet_iac(telnet_t *telnet, unsigned char cmd); 403 404 /* 405 * Send negotiation command. 406 * 407 * Internally, libTELNET uses RFC1143 option negotiation rules. 408 * The negotiation commands sent with this function may be ignored 409 * if they are determined to be redundant. 410 * 411 * param telnet Telnet state tracker object. 412 * param cmd TELNET_WILL, TELNET_WONT, TELNET_DO, or TELNET_DONT. 413 * param opt One of the TELNET_TELOPT_* values. 414 */ 415 extern void telnet_negotiate(telnet_t *telnet, unsigned char cmd, 416 unsigned char opt); 417 418 /* 419 * Send non-command data (escapes IAC bytes). 420 * 421 * param telnet Telnet state tracker object. 422 * param buffer Buffer of bytes to send. 423 * param size Number of bytes to send. 424 */ 425 extern void telnet_send(telnet_t *telnet, 426 const char *buffer, size_t size); 427 428 /* 429 * Send non-command text (escapes IAC bytes and translates 430 * \\r -> CR-NUL and \\n -> CR-LF unless in BINARY mode. 431 * 432 * param telnet Telnet state tracker object. 433 * param buffer Buffer of bytes to send. 434 * param size Number of bytes to send. 435 */ 436 extern void telnet_send_text(telnet_t *telnet, 437 const char *buffer, size_t size); 438 439 /* 440 * Begin a sub-negotiation command. 441 * 442 * Sends IAC SB followed by the telopt code. All following data sent 443 * will be part of the sub-negotiation, until telnet_finish_sb() is 444 * called. 445 * 446 * param telnet Telnet state tracker object. 447 * param telopt One of the TELNET_TELOPT_* values. 448 */ 449 extern void telnet_begin_sb(telnet_t *telnet, 450 unsigned char telopt); 451 452 /* 453 * Finish a sub-negotiation command. 454 * 455 * This must be called after a call to telnet_begin_sb() to finish a 456 * sub-negotiation command. 457 * 458 * param telnet Telnet state tracker object. 459 */ 460 # define telnet_finish_sb(telnet) telnet_iac((telnet), TELNET_SE) 461 462 /* 463 * Send formatted data. 464 * 465 * This function is a wrapper around telnet_send(). It allows using 466 * printf-style formatting. 467 * 468 * Additionally, this function will translate \\r to the CR NUL construct and 469 * \\n with CR LF, as well as automatically escaping IAC bytes like 470 * telnet_send(). 471 * 472 * param telnet Telnet state tracker object. 473 * param fmt Format string. 474 * return Number of bytes sent. 475 */ 476 extern int telnet_printf(telnet_t *telnet, const char *fmt, ...) 477 TELNET_GNU_PRINTF(2, 3); 478 479 /* 480 * Send formatted data. 481 * 482 * See telnet_printf(). 483 */ 484 extern int telnet_vprintf(telnet_t *telnet, const char *fmt, va_list va); 485 486 /* 487 * Send formatted data (no newline escaping). 488 * 489 * This behaves identically to telnet_printf(), except that the \\r and \\n 490 * characters are not translated. The IAC byte is still escaped as normal 491 * with telnet_send(). 492 * 493 * param telnet Telnet state tracker object. 494 * param fmt Format string. 495 * return Number of bytes sent. 496 */ 497 extern int telnet_raw_printf(telnet_t *telnet, const char *fmt, ...) 498 TELNET_GNU_PRINTF(2, 3); 499 500 /* 501 * Send formatted data (no newline escaping). 502 * 503 * See telnet_raw_printf(). 504 */ 505 extern int telnet_raw_vprintf(telnet_t *telnet, const char *fmt, va_list va); 506 507 #endif /* !defined(LIBTELNET_INCLUDE) */