1 /*
2 * vim: filetype=c:tabstop=4:ai:expandtab
3 * SPDX-License-Identifier: CC-PDDC
4 * SPDX-FileCopyrightText: Public domain
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, void *user_data);
368
369 /*
370 * Free up any memory allocated by a state tracker.
371 *
372 * This function must be called when a telnet state tracker is no
373 * longer needed (such as after the connection has been closed) to
374 * release any memory resources used by the state tracker.
375 *
376 * param telnet Telnet state tracker object.
377 */
378 extern void telnet_free(telnet_t *telnet);
379
380 /*
381 * Push a byte buffer into the state tracker.
382 *
383 * Passes one or more bytes to the telnet state tracker for
384 * protocol parsing. The byte buffer is most often going to be
385 * the buffer that recv() was called for while handling the
386 * connection.
387 *
388 * param telnet Telnet state tracker object.
389 * param buffer Pointer to byte buffer.
390 * param size Number of bytes pointed to by buffer.
391 */
392 extern void telnet_recv(telnet_t *telnet, const char *buffer,
393 size_t size);
394
395 /*
396 * Send a telnet command.
397 *
398 * param telnet Telnet state tracker object.
399 * param cmd Command to send.
400 */
401 extern void telnet_iac(telnet_t *telnet, unsigned char cmd);
402
403 /*
404 * Send negotiation command.
405 *
406 * Internally, libTELNET uses RFC1143 option negotiation rules.
407 * The negotiation commands sent with this function may be ignored
408 * if they are determined to be redundant.
409 *
410 * param telnet Telnet state tracker object.
411 * param cmd TELNET_WILL, TELNET_WONT, TELNET_DO, or TELNET_DONT.
412 * param opt One of the TELNET_TELOPT_* values.
413 */
414 extern void telnet_negotiate(telnet_t *telnet, unsigned char cmd,
415 unsigned char opt);
416
417 /*
418 * Send non-command data (escapes IAC bytes).
419 *
420 * param telnet Telnet state tracker object.
421 * param buffer Buffer of bytes to send.
422 * param size Number of bytes to send.
423 */
424 extern void telnet_send(telnet_t *telnet,
425 const char *buffer, size_t size);
426
427 /*
428 * Send non-command text (escapes IAC bytes and translates
429 * \\r -> CR-NUL and \\n -> CR-LF unless in BINARY mode.
430 *
431 * param telnet Telnet state tracker object.
432 * param buffer Buffer of bytes to send.
433 * param size Number of bytes to send.
434 */
435 extern void telnet_send_text(telnet_t *telnet,
436 const char *buffer, size_t size);
437
438 /*
439 * Begin a sub-negotiation command.
440 *
441 * Sends IAC SB followed by the telopt code. All following data sent
442 * will be part of the sub-negotiation, until telnet_finish_sb() is
443 * called.
444 *
445 * param telnet Telnet state tracker object.
446 * param telopt One of the TELNET_TELOPT_* values.
447 */
448 extern void telnet_begin_sb(telnet_t *telnet,
449 unsigned char telopt);
450
451 /*
452 * Finish a sub-negotiation command.
453 *
454 * This must be called after a call to telnet_begin_sb() to finish a
455 * sub-negotiation command.
456 *
457 * param telnet Telnet state tracker object.
458 */
459 # define telnet_finish_sb(telnet) telnet_iac((telnet), TELNET_SE)
460
461 /*
462 * Send formatted data.
463 *
464 * This function is a wrapper around telnet_send(). It allows using
465 * printf-style formatting.
466 *
467 * Additionally, this function will translate \\r to the CR NUL construct and
468 * \\n with CR LF, as well as automatically escaping IAC bytes like
469 * telnet_send().
470 *
471 * param telnet Telnet state tracker object.
472 * param fmt Format string.
473 * return Number of bytes sent.
474 */
475 extern int telnet_printf(telnet_t *telnet, const char *fmt, ...)
476 TELNET_GNU_PRINTF(2, 3);
477
478 /*
479 * Send formatted data.
480 *
481 * See telnet_printf().
482 */
483 extern int telnet_vprintf(telnet_t *telnet, const char *fmt, va_list va);
484
485 /*
486 * Send formatted data (no newline escaping).
487 *
488 * This behaves identically to telnet_printf(), except that the \\r and \\n
489 * characters are not translated. The IAC byte is still escaped as normal
490 * with telnet_send().
491 *
492 * param telnet Telnet state tracker object.
493 * param fmt Format string.
494 * return Number of bytes sent.
495 */
496 extern int telnet_raw_printf(telnet_t *telnet, const char *fmt, ...)
497 TELNET_GNU_PRINTF(2, 3);
498
499 /*
500 * Send formatted data (no newline escaping).
501 *
502 * See telnet_raw_printf().
503 */
504 extern int telnet_raw_vprintf(telnet_t *telnet, const char *fmt, va_list va);
505
506 #endif /* !defined(LIBTELNET_INCLUDE) */