Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-rlogin.c
blob2fb41efe64cdf970c8252e8842f18505c8a490b3
1 /* packet-rlogin.c
2 * Routines for unix rlogin packet dissection
3 * Copyright 2000, Jeffrey C. Foster <jfoste[AT]woodward.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * Based upon RFC-1282 - BSD Rlogin
11 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include "config.h"
16 #include <stdlib.h>
17 #include <epan/packet.h>
18 #include <epan/expert.h>
19 #include <wsutil/strtoi.h>
20 #include "packet-tcp.h"
22 #define RLOGIN_PORT 513
24 void proto_register_rlogin(void);
25 void proto_reg_handoff_rlogin(void);
27 static dissector_handle_t rlogin_handle;
29 static int proto_rlogin;
31 static int ett_rlogin;
32 static int ett_rlogin_window;
33 static int ett_rlogin_user_info;
34 static int ett_rlogin_window_rows;
35 static int ett_rlogin_window_cols;
36 static int ett_rlogin_window_x_pixels;
37 static int ett_rlogin_window_y_pixels;
39 static int hf_user_info;
40 static int hf_client_startup_flag;
41 static int hf_startup_info_received_flag;
42 static int hf_user_info_client_user_name;
43 static int hf_user_info_server_user_name;
44 static int hf_user_info_terminal_type;
45 static int hf_user_info_terminal_speed;
46 static int hf_control_message;
47 static int hf_magic_cookie;
48 static int hf_window_info;
49 static int hf_window_info_ss;
50 static int hf_window_info_rows;
51 static int hf_window_info_cols;
52 static int hf_window_info_x_pixels;
53 static int hf_window_info_y_pixels;
54 static int hf_data;
56 static expert_field ei_rlogin_termlen_invalid;
58 static const value_string control_message_vals[] =
60 { 0x02, "Clear buffer" },
61 { 0x10, "Raw mode" },
62 { 0x20, "Cooked mode" },
63 { 0x80, "Window size request" },
64 { 0, NULL }
68 typedef enum {
69 NONE=0,
70 USER_INFO_WAIT=1,
71 DONE=2
72 } session_state_t;
74 #define NAME_LEN 32
75 typedef struct {
76 session_state_t state;
77 uint32_t info_framenum;
78 char user_name[NAME_LEN];
79 } rlogin_hash_entry_t;
83 /* Decoder State Machine. Currently only used to snoop on
84 client-user-name as sent by the client up connection establishment.
86 static void
87 rlogin_state_machine(rlogin_hash_entry_t *hash_info, tvbuff_t *tvb, packet_info *pinfo)
89 unsigned length;
90 int stringlen;
92 /* Won't change state if already seen this packet */
93 if (pinfo->fd->visited)
95 return;
98 /* rlogin stream decoder */
99 /* Just watch for the second packet from client with the user name and */
100 /* terminal type information. */
102 if (pinfo->destport != RLOGIN_PORT)
104 return;
107 /* exit if already passed username in conversation */
108 if (hash_info->state == DONE)
110 return;
113 /* exit if no data */
114 length = tvb_captured_length(tvb);
115 if (length == 0)
117 return;
120 if (hash_info->state == NONE)
122 /* new connection*/
123 if (tvb_get_uint8(tvb, 0) != '\0')
125 /* We expected a null, but didn't get one; quit. */
126 hash_info->state = DONE;
127 return;
129 else
131 if (length <= 1)
133 /* Still waiting for data */
134 hash_info->state = USER_INFO_WAIT;
136 else
138 /* Have info, store frame number */
139 hash_info->state = DONE;
140 hash_info->info_framenum = pinfo->num;
144 /* expect user data here */
145 /* TODO: may need to do more checking here? */
146 else
147 if (hash_info->state == USER_INFO_WAIT)
149 /* Store frame number here */
150 hash_info->state = DONE;
151 hash_info->info_framenum = pinfo->num;
153 /* Work out length of string to copy */
154 stringlen = tvb_strnlen(tvb, 0, NAME_LEN);
155 if (stringlen == -1)
156 stringlen = NAME_LEN - 1; /* no '\0' found */
157 else if (stringlen > NAME_LEN - 1)
158 stringlen = NAME_LEN - 1; /* name too long */
160 /* Copy and terminate string into hash name */
161 tvb_memcpy(tvb, (uint8_t *)hash_info->user_name, 0, stringlen);
162 hash_info->user_name[stringlen] = '\0';
164 col_append_str(pinfo->cinfo, COL_INFO, ", (User information)");
168 /* Dissect details of packet */
169 static void rlogin_display(rlogin_hash_entry_t *hash_info,
170 tvbuff_t *tvb,
171 packet_info *pinfo,
172 proto_tree *tree,
173 struct tcpinfo *tcpinfo)
175 /* Display the proto tree */
176 int offset = 0;
177 proto_tree *rlogin_tree, *user_info_tree, *window_tree;
178 proto_item *ti;
179 unsigned length;
180 int str_len;
181 int ti_offset;
182 proto_item *user_info_item, *window_info_item;
184 /* Create rlogin subtree */
185 ti = proto_tree_add_item(tree, proto_rlogin, tvb, 0, -1, ENC_NA);
186 rlogin_tree = proto_item_add_subtree(ti, ett_rlogin);
188 /* Return if data empty */
189 length = tvb_captured_length(tvb);
190 if (length == 0)
192 return;
196 * XXX - this works only if the urgent pointer points to something
197 * in this segment; to make it work if the urgent pointer points
198 * to something past this segment, we'd have to remember the urgent
199 * pointer setting for this conversation.
201 if (tcpinfo && IS_TH_URG(tcpinfo->flags) && /* if urgent pointer set */
202 length >= tcpinfo->urgent_pointer) /* and it's in this frame */
204 /* Get urgent byte into Temp */
205 int urgent_offset = tcpinfo->urgent_pointer - 1;
206 uint8_t control_byte;
208 /* Check for text data in front */
209 if (urgent_offset > offset)
211 proto_tree_add_item(rlogin_tree, hf_data, tvb, offset, urgent_offset, ENC_ASCII);
214 /* Show control byte */
215 proto_tree_add_item(rlogin_tree, hf_control_message, tvb,
216 urgent_offset, 1, ENC_BIG_ENDIAN);
217 control_byte = tvb_get_uint8(tvb, urgent_offset);
218 col_append_fstr(pinfo->cinfo, COL_INFO,
219 " (%s)", val_to_str_const(control_byte, control_message_vals, "Unknown"));
221 offset = urgent_offset + 1; /* adjust offset */
223 else
224 if (tvb_get_uint8(tvb, offset) == '\0')
226 /* Startup */
227 if (pinfo->srcport == RLOGIN_PORT) /* from server */
229 proto_tree_add_item(rlogin_tree, hf_startup_info_received_flag,
230 tvb, offset, 1, ENC_BIG_ENDIAN);
232 else
234 proto_tree_add_item(rlogin_tree, hf_client_startup_flag,
235 tvb, offset, 1, ENC_BIG_ENDIAN);
237 ++offset;
240 if (!tvb_offset_exists(tvb, offset))
242 /* No more data to check */
243 return;
246 if (hash_info->info_framenum == pinfo->num)
248 int info_len;
249 int slash_offset;
251 /* First frame of conversation, assume user info... */
253 info_len = tvb_captured_length_remaining(tvb, offset);
254 if (info_len <= 0)
255 return;
257 /* User info tree */
258 user_info_item = proto_tree_add_string_format(rlogin_tree, hf_user_info, tvb,
259 offset, info_len, NULL,
260 "User info (%s)",
261 tvb_format_text(pinfo->pool, tvb, offset, info_len));
262 user_info_tree = proto_item_add_subtree(user_info_item,
263 ett_rlogin_user_info);
265 /* Client user name. */
266 str_len = tvb_strsize(tvb, offset);
267 proto_tree_add_item(user_info_tree, hf_user_info_client_user_name,
268 tvb, offset, str_len, ENC_ASCII);
269 offset += str_len;
271 /* Server user name. */
272 str_len = tvb_strsize(tvb, offset);
273 proto_tree_add_item(user_info_tree, hf_user_info_server_user_name,
274 tvb, offset, str_len, ENC_ASCII);
275 offset += str_len;
277 /* Terminal type/speed. */
278 slash_offset = tvb_find_uint8(tvb, offset, -1, '/');
279 if (slash_offset != -1)
281 uint8_t* str = NULL;
282 uint32_t term_len = 0;
283 bool term_len_valid;
284 proto_item* pi = NULL;
286 /* Terminal type */
287 proto_tree_add_item(user_info_tree, hf_user_info_terminal_type,
288 tvb, offset, slash_offset-offset, ENC_ASCII);
289 offset = slash_offset + 1;
291 /* Terminal speed */
292 str_len = tvb_strsize(tvb, offset);
293 str = tvb_get_string_enc(pinfo->pool, tvb, offset, str_len,
294 ENC_NA|ENC_ASCII);
295 term_len_valid = ws_strtou32(str, NULL, &term_len);
296 pi = proto_tree_add_uint(user_info_tree,
297 hf_user_info_terminal_speed,
298 tvb, offset, str_len, term_len);
299 if (!term_len_valid)
300 expert_add_info(pinfo, pi, &ei_rlogin_termlen_invalid);
302 offset += str_len;
306 if (!tvb_offset_exists(tvb, offset))
308 /* No more data to check */
309 return;
312 /* Test for terminal information, the data will have 2 0xff bytes */
313 /* look for first 0xff byte */
314 ti_offset = tvb_find_uint8(tvb, offset, -1, 0xff);
316 /* Next byte must also be 0xff */
317 if (ti_offset != -1 &&
318 tvb_bytes_exist(tvb, ti_offset + 1, 1) &&
319 tvb_get_uint8(tvb, ti_offset + 1) == 0xff)
321 uint16_t rows, columns;
323 /* Have found terminal info. */
324 if (ti_offset > offset)
326 /* There's data before the terminal info. */
327 proto_tree_add_item(rlogin_tree, hf_data, tvb,
328 offset, ti_offset - offset, ENC_ASCII);
331 /* Create window info tree */
332 window_info_item =
333 proto_tree_add_item(rlogin_tree, hf_window_info, tvb, offset, 12, ENC_NA);
334 window_tree = proto_item_add_subtree(window_info_item, ett_rlogin_window);
336 /* Cookie */
337 proto_tree_add_item(window_tree, hf_magic_cookie, tvb, offset, 2, ENC_BIG_ENDIAN);
338 offset += 2;
340 /* These bytes should be "ss" */
341 proto_tree_add_item(window_tree, hf_window_info_ss, tvb, offset, 2, ENC_ASCII);
342 offset += 2;
344 /* Character rows */
345 rows = tvb_get_ntohs(tvb, offset);
346 proto_tree_add_item(window_tree, hf_window_info_rows, tvb,
347 offset, 2, ENC_BIG_ENDIAN);
348 offset += 2;
350 /* Characters per row */
351 columns = tvb_get_ntohs(tvb, offset);
352 proto_tree_add_item(window_tree, hf_window_info_cols, tvb,
353 offset, 2, ENC_BIG_ENDIAN);
354 offset += 2;
356 /* x pixels */
357 proto_tree_add_item(window_tree, hf_window_info_x_pixels, tvb,
358 offset, 2, ENC_BIG_ENDIAN);
359 offset += 2;
361 /* y pixels */
362 proto_tree_add_item(window_tree, hf_window_info_y_pixels, tvb,
363 offset, 2, ENC_BIG_ENDIAN);
364 offset += 2;
366 /* Show setting highlights in info column */
367 col_append_fstr(pinfo->cinfo, COL_INFO, " (rows=%u, cols=%u)",
368 rows, columns);
371 if (tvb_offset_exists(tvb, offset))
373 /* There's more data in the frame. */
374 proto_tree_add_item(rlogin_tree, hf_data, tvb, offset, -1, ENC_ASCII);
379 /****************************************************************
380 * Main dissection function
381 ****************************************************************/
382 static int
383 dissect_rlogin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
385 struct tcpinfo *tcpinfo = (struct tcpinfo *)data;
386 conversation_t *conversation;
387 rlogin_hash_entry_t *hash_info;
388 unsigned length;
389 int ti_offset;
391 /* Get or create conversation */
392 conversation = find_or_create_conversation(pinfo);
394 /* Get or create data associated with this conversation */
395 hash_info = (rlogin_hash_entry_t *)conversation_get_proto_data(conversation, proto_rlogin);
396 if (!hash_info)
398 /* Populate new data struct... */
399 hash_info = wmem_new(wmem_file_scope(), rlogin_hash_entry_t);
400 hash_info->state = NONE;
401 hash_info->info_framenum = 0; /* no frame has the number 0 */
402 hash_info->user_name[0] = '\0';
404 /* ... and store in conversation */
405 conversation_add_proto_data(conversation, proto_rlogin, hash_info);
408 /* Set protocol column text */
409 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Rlogin");
411 /* Set info column */
412 /* Show user-name if available */
413 if (hash_info->user_name[0])
415 col_add_fstr(pinfo->cinfo, COL_INFO,
416 "User name: %s, ", hash_info->user_name);
418 else
420 col_clear(pinfo->cinfo, COL_INFO);
423 /* Work out packet content summary for display */
424 length = tvb_reported_length(tvb);
425 if (length != 0)
427 /* Initial NULL byte represents part of connection handshake */
428 if (tvb_get_uint8(tvb, 0) == '\0')
430 col_append_str(pinfo->cinfo, COL_INFO,
431 (pinfo->destport == RLOGIN_PORT) ?
432 "Start Handshake" :
433 "Startup info received");
435 else
436 if (tcpinfo && IS_TH_URG(tcpinfo->flags) && length >= tcpinfo->urgent_pointer)
438 /* Urgent pointer inside current data represents a control message */
439 col_append_str(pinfo->cinfo, COL_INFO, "Control Message");
441 else
443 /* Search for 2 consecutive ff bytes
444 (signifies window change control message) */
445 ti_offset = tvb_find_uint8(tvb, 0, -1, 0xff);
446 if (ti_offset != -1 &&
447 tvb_bytes_exist(tvb, ti_offset + 1, 1) &&
448 tvb_get_uint8(tvb, ti_offset + 1) == 0xff)
450 col_append_str(pinfo->cinfo, COL_INFO, "Terminal Info");
452 else
454 /* Show any text data in the frame */
455 int bytes_to_copy = tvb_captured_length(tvb);
456 if (bytes_to_copy > 128)
458 /* Truncate to 128 bytes for display */
459 bytes_to_copy = 128;
462 /* Add data into info column */
463 col_append_fstr(pinfo->cinfo, COL_INFO,
464 "Data: %s",
465 tvb_format_text(pinfo->pool, tvb, 0, bytes_to_copy));
470 /* See if conversation state needs to be updated */
471 rlogin_state_machine(hash_info, tvb, pinfo);
473 /* Dissect in detail */
474 rlogin_display(hash_info, tvb, pinfo, tree, tcpinfo);
476 return tvb_captured_length(tvb);
480 void proto_register_rlogin(void)
482 expert_module_t* expert_rlogin;
484 static int *ett[] = {
485 &ett_rlogin,
486 &ett_rlogin_window,
487 &ett_rlogin_window_rows,
488 &ett_rlogin_window_cols,
489 &ett_rlogin_window_x_pixels,
490 &ett_rlogin_window_y_pixels,
491 &ett_rlogin_user_info
494 static hf_register_info hf[] =
496 { &hf_user_info,
497 { "User Info", "rlogin.user_info", FT_STRING, BASE_NONE,
498 NULL, 0x0, NULL, HFILL
501 { &hf_client_startup_flag,
502 { "Client startup flag", "rlogin.client_startup_flag", FT_UINT8, BASE_HEX,
503 NULL, 0x0, NULL, HFILL
506 { &hf_startup_info_received_flag,
507 { "Startup info received flag", "rlogin.startup_info_received_flag", FT_UINT8, BASE_HEX,
508 NULL, 0x0, NULL, HFILL
511 { &hf_user_info_client_user_name,
512 { "Client-user-name", "rlogin.client_user_name", FT_STRING, BASE_NONE,
513 NULL, 0x0, NULL, HFILL
516 { &hf_user_info_server_user_name,
517 { "Server-user-name", "rlogin.server_user_name", FT_STRING, BASE_NONE,
518 NULL, 0x0, NULL, HFILL
521 { &hf_user_info_terminal_type,
522 { "Terminal-type", "rlogin.terminal_type", FT_STRING, BASE_NONE,
523 NULL, 0x0, NULL, HFILL
526 { &hf_user_info_terminal_speed,
527 { "Terminal-speed", "rlogin.terminal_speed", FT_UINT32, BASE_DEC,
528 NULL, 0x0, NULL, HFILL
531 { &hf_control_message,
532 { "Control message", "rlogin.control_message", FT_UINT8, BASE_HEX,
533 VALS(control_message_vals), 0x0, NULL, HFILL
536 { &hf_magic_cookie,
537 { "Magic Cookie", "rlogin.magic_cookie", FT_UINT16, BASE_HEX,
538 NULL, 0x0, NULL, HFILL
541 { &hf_window_info,
542 { "Window Info", "rlogin.window_size", FT_NONE, BASE_NONE,
543 NULL, 0x0, NULL, HFILL
546 { &hf_window_info_ss,
547 { "Window size marker", "rlogin.window_size.ss", FT_STRING, BASE_NONE,
548 NULL, 0x0, NULL, HFILL
551 { &hf_window_info_rows,
552 { "Rows", "rlogin.window_size.rows", FT_UINT16, BASE_DEC,
553 NULL, 0x0, NULL, HFILL
556 { &hf_window_info_cols,
557 { "Columns", "rlogin.window_size.cols", FT_UINT16, BASE_DEC,
558 NULL, 0x0, NULL, HFILL
561 { &hf_window_info_x_pixels,
562 { "X Pixels", "rlogin.window_size.x_pixels", FT_UINT16, BASE_DEC,
563 NULL, 0x0, NULL, HFILL
566 { &hf_window_info_y_pixels,
567 { "Y Pixels", "rlogin.window_size.y_pixels", FT_UINT16, BASE_DEC,
568 NULL, 0x0, NULL, HFILL
571 { &hf_data,
572 { "Data", "rlogin.data", FT_STRING, BASE_NONE,
573 NULL, 0x0, NULL, HFILL
578 static ei_register_info ei[] = {
579 { &ei_rlogin_termlen_invalid, { "rlogin.terminal_speed.invalid", PI_MALFORMED, PI_ERROR,
580 "Terminal length must be a string containing an integer", EXPFILL }}
583 proto_rlogin = proto_register_protocol("Rlogin Protocol", "Rlogin", "rlogin");
585 proto_register_field_array(proto_rlogin, hf, array_length(hf));
586 proto_register_subtree_array(ett, array_length(ett));
588 expert_rlogin = expert_register_protocol(proto_rlogin);
589 expert_register_field_array(expert_rlogin, ei, array_length(ei));
591 rlogin_handle = register_dissector("rlogin", dissect_rlogin,proto_rlogin);
594 void proto_reg_handoff_rlogin(void)
596 /* Dissector install routine */
597 dissector_add_uint_with_preference("tcp.port", RLOGIN_PORT, rlogin_handle);
601 * Editor modelines - https://www.wireshark.org/tools/modelines.html
603 * Local variables:
604 * c-basic-offset: 8
605 * tab-width: 8
606 * indent-tabs-mode: t
607 * End:
609 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
610 * :indentSize=8:tabSize=8:noTabs=false: