MSWSP: add two more Property Sets
[wireshark-wip.git] / epan / dissectors / packet-rlogin.c
blob87703ae458fd9bdce4b2558eeae917c00764ada1
1 /* packet-rlogin.c
2 * Routines for unix rlogin packet dissection
3 * Copyright 2000, Jeffrey C. Foster <jfoste[AT]woodward.com>
5 * $Id$
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * Based upon RFC-1282 - BSD Rlogin
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "config.h"
30 #include <stdlib.h>
31 #include <string.h>
32 #include <glib.h>
34 #include <epan/packet.h>
35 #include <epan/conversation.h>
36 #include <epan/wmem/wmem.h>
38 #include "packet-tcp.h"
40 #define RLOGIN_PORT 513
42 static int proto_rlogin = -1;
44 static int ett_rlogin = -1;
45 static int ett_rlogin_window = -1;
46 static int ett_rlogin_user_info = -1;
47 static int ett_rlogin_window_rows = -1;
48 static int ett_rlogin_window_cols = -1;
49 static int ett_rlogin_window_x_pixels = -1;
50 static int ett_rlogin_window_y_pixels = -1;
52 static int hf_user_info = -1;
53 static int hf_client_startup_flag = -1;
54 static int hf_startup_info_received_flag = -1;
55 static int hf_user_info_client_user_name = -1;
56 static int hf_user_info_server_user_name = -1;
57 static int hf_user_info_terminal_type = -1;
58 static int hf_user_info_terminal_speed = -1;
59 static int hf_control_message = -1;
60 static int hf_window_info = -1;
61 static int hf_window_info_ss = -1;
62 static int hf_window_info_rows = -1;
63 static int hf_window_info_cols = -1;
64 static int hf_window_info_x_pixels = -1;
65 static int hf_window_info_y_pixels = -1;
66 static int hf_data = -1;
68 static const value_string control_message_vals[] =
70 { 0x02, "Clear buffer" },
71 { 0x10, "Raw mode" },
72 { 0x20, "Cooked mode" },
73 { 0x80, "Window size request" },
74 { 0, NULL }
78 typedef enum {
79 NONE=0,
80 USER_INFO_WAIT=1,
81 DONE=2
82 } session_state_t;
84 #define NAME_LEN 32
85 typedef struct {
86 session_state_t state;
87 guint32 info_framenum;
88 char user_name[NAME_LEN];
89 } rlogin_hash_entry_t;
93 /* Decoder State Machine. Currently only used to snoop on
94 client-user-name as sent by the client up connection establishment.
96 static void
97 rlogin_state_machine(rlogin_hash_entry_t *hash_info, tvbuff_t *tvb, packet_info *pinfo)
99 guint length;
100 gint stringlen;
102 /* Won't change state if already seen this packet */
103 if (pinfo->fd->flags.visited)
105 return;
108 /* rlogin stream decoder */
109 /* Just watch for the second packet from client with the user name and */
110 /* terminal type information. */
112 if (pinfo->destport != RLOGIN_PORT)
114 return;
117 /* exit if already passed username in conversation */
118 if (hash_info->state == DONE)
120 return;
123 /* exit if no data */
124 length = tvb_length(tvb);
125 if (length == 0)
127 return;
130 if (hash_info->state == NONE)
132 /* new connection*/
133 if (tvb_get_guint8(tvb, 0) != '\0')
135 /* We expected a null, but didn't get one; quit. */
136 hash_info->state = DONE;
137 return;
139 else
141 if (length <= 1)
143 /* Still waiting for data */
144 hash_info->state = USER_INFO_WAIT;
146 else
148 /* Have info, store frame number */
149 hash_info->state = DONE;
150 hash_info->info_framenum = pinfo->fd->num;
154 /* expect user data here */
155 /* TODO: may need to do more checking here? */
156 else
157 if (hash_info->state == USER_INFO_WAIT)
159 /* Store frame number here */
160 hash_info->state = DONE;
161 hash_info->info_framenum = pinfo->fd->num;
163 /* Work out length of string to copy */
164 stringlen = tvb_strnlen(tvb, 0, NAME_LEN);
165 if (stringlen == -1)
166 stringlen = NAME_LEN - 1; /* no '\0' found */
167 else if (stringlen > NAME_LEN - 1)
168 stringlen = NAME_LEN - 1; /* name too long */
170 /* Copy and terminate string into hash name */
171 tvb_memcpy(tvb, (guint8 *)hash_info->user_name, 0, stringlen);
172 hash_info->user_name[stringlen] = '\0';
174 col_append_str(pinfo->cinfo, COL_INFO, ", (User information)");
178 /* Dissect details of packet */
179 static void rlogin_display(rlogin_hash_entry_t *hash_info,
180 tvbuff_t *tvb,
181 packet_info *pinfo,
182 proto_tree *tree,
183 struct tcpinfo *tcpinfo)
185 /* Display the proto tree */
186 int offset = 0;
187 proto_tree *rlogin_tree, *user_info_tree, *window_tree;
188 proto_item *ti;
189 guint length;
190 int str_len;
191 gint ti_offset;
192 proto_item *user_info_item, *window_info_item;
194 /* Create rlogin subtree */
195 ti = proto_tree_add_item(tree, proto_rlogin, tvb, 0, -1, ENC_NA);
196 rlogin_tree = proto_item_add_subtree(ti, ett_rlogin);
198 /* Return if data empty */
199 length = tvb_length(tvb);
200 if (length == 0)
202 return;
206 * XXX - this works only if the urgent pointer points to something
207 * in this segment; to make it work if the urgent pointer points
208 * to something past this segment, we'd have to remember the urgent
209 * pointer setting for this conversation.
211 if (tcpinfo->urgent && /* if urgent pointer set */
212 length >= tcpinfo->urgent_pointer) /* and it's in this frame */
214 /* Get urgent byte into Temp */
215 int urgent_offset = tcpinfo->urgent_pointer - 1;
216 guint8 control_byte;
218 /* Check for text data in front */
219 if (urgent_offset > offset)
221 proto_tree_add_item(rlogin_tree, hf_data, tvb, offset, urgent_offset, ENC_ASCII|ENC_NA);
224 /* Show control byte */
225 proto_tree_add_item(rlogin_tree, hf_control_message, tvb,
226 urgent_offset, 1, ENC_BIG_ENDIAN);
227 control_byte = tvb_get_guint8(tvb, urgent_offset);
228 col_append_fstr(pinfo->cinfo, COL_INFO,
229 " (%s)", val_to_str_const(control_byte, control_message_vals, "Unknown"));
231 offset = urgent_offset + 1; /* adjust offset */
233 else
234 if (tvb_get_guint8(tvb, offset) == '\0')
236 /* Startup */
237 if (pinfo->srcport == RLOGIN_PORT) /* from server */
239 proto_tree_add_item(rlogin_tree, hf_startup_info_received_flag,
240 tvb, offset, 1, ENC_BIG_ENDIAN);
242 else
244 proto_tree_add_item(rlogin_tree, hf_client_startup_flag,
245 tvb, offset, 1, ENC_BIG_ENDIAN);
247 ++offset;
250 if (!tvb_offset_exists(tvb, offset))
252 /* No more data to check */
253 return;
256 if (hash_info->info_framenum == pinfo->fd->num)
258 gint info_len;
259 gint slash_offset;
261 /* First frame of conversation, assume user info... */
263 info_len = tvb_length_remaining(tvb, offset);
264 if (info_len <= 0)
265 return;
267 /* User info tree */
268 user_info_item = proto_tree_add_string_format(rlogin_tree, hf_user_info, tvb,
269 offset, info_len, FALSE,
270 "User info (%s)",
271 tvb_format_text(tvb, offset, info_len));
272 user_info_tree = proto_item_add_subtree(user_info_item,
273 ett_rlogin_user_info);
275 /* Client user name. */
276 str_len = tvb_strsize(tvb, offset);
277 proto_tree_add_item(user_info_tree, hf_user_info_client_user_name,
278 tvb, offset, str_len, ENC_ASCII|ENC_NA);
279 offset += str_len;
281 /* Server user name. */
282 str_len = tvb_strsize(tvb, offset);
283 proto_tree_add_item(user_info_tree, hf_user_info_server_user_name,
284 tvb, offset, str_len, ENC_ASCII|ENC_NA);
285 offset += str_len;
287 /* Terminal type/speed. */
288 slash_offset = tvb_find_guint8(tvb, offset, -1, '/');
289 if (slash_offset != -1)
291 /* Terminal type */
292 proto_tree_add_item(user_info_tree, hf_user_info_terminal_type,
293 tvb, offset, slash_offset-offset, ENC_ASCII|ENC_NA);
294 offset = slash_offset + 1;
296 /* Terminal speed */
297 str_len = tvb_strsize(tvb, offset);
298 proto_tree_add_uint(user_info_tree, hf_user_info_terminal_speed,
299 tvb, offset, str_len,
300 atoi(tvb_format_text(tvb, offset, str_len)));
301 offset += str_len;
305 if (!tvb_offset_exists(tvb, offset))
307 /* No more data to check */
308 return;
311 /* Test for terminal information, the data will have 2 0xff bytes */
312 /* look for first 0xff byte */
313 ti_offset = tvb_find_guint8(tvb, offset, -1, 0xff);
315 /* Next byte must also be 0xff */
316 if (ti_offset != -1 &&
317 tvb_bytes_exist(tvb, ti_offset + 1, 1) &&
318 tvb_get_guint8(tvb, ti_offset + 1) == 0xff)
320 guint16 rows, columns;
322 /* Have found terminal info. */
323 if (ti_offset > offset)
325 /* There's data before the terminal info. */
326 proto_tree_add_item(rlogin_tree, hf_data, tvb,
327 offset, ti_offset - offset, ENC_ASCII|ENC_NA);
330 /* Create window info tree */
331 window_info_item =
332 proto_tree_add_item(rlogin_tree, hf_window_info, tvb, offset, 12, ENC_NA);
333 window_tree = proto_item_add_subtree(window_info_item, ett_rlogin_window);
335 /* Cookie */
336 proto_tree_add_text(window_tree, tvb, offset, 2, "Magic Cookie: (0xff, 0xff)");
337 offset += 2;
339 /* These bytes should be "ss" */
340 proto_tree_add_item(window_tree, hf_window_info_ss, tvb, offset, 2, ENC_ASCII|ENC_NA);
341 offset += 2;
343 /* Character rows */
344 rows = tvb_get_ntohs(tvb, offset);
345 proto_tree_add_item(window_tree, hf_window_info_rows, tvb,
346 offset, 2, ENC_BIG_ENDIAN);
347 offset += 2;
349 /* Characters per row */
350 columns = tvb_get_ntohs(tvb, offset);
351 proto_tree_add_item(window_tree, hf_window_info_cols, tvb,
352 offset, 2, ENC_BIG_ENDIAN);
353 offset += 2;
355 /* x pixels */
356 proto_tree_add_item(window_tree, hf_window_info_x_pixels, tvb,
357 offset, 2, ENC_BIG_ENDIAN);
358 offset += 2;
360 /* y pixels */
361 proto_tree_add_item(window_tree, hf_window_info_y_pixels, tvb,
362 offset, 2, ENC_BIG_ENDIAN);
363 offset += 2;
365 /* Show setting highlights in info column */
366 col_append_fstr(pinfo->cinfo, COL_INFO, " (rows=%u, cols=%u)",
367 rows, columns);
370 if (tvb_offset_exists(tvb, offset))
372 /* There's more data in the frame. */
373 proto_tree_add_item(rlogin_tree, hf_data, tvb, offset, -1, ENC_ASCII|ENC_NA);
378 /****************************************************************
379 * Main dissection function
380 ****************************************************************/
381 static int
382 dissect_rlogin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
384 struct tcpinfo *tcpinfo = (struct tcpinfo *)data;
385 conversation_t *conversation;
386 rlogin_hash_entry_t *hash_info;
387 guint length;
388 gint ti_offset;
390 /* Get or create conversation */
391 conversation = find_or_create_conversation(pinfo);
393 /* Get or create data associated with this conversation */
394 hash_info = (rlogin_hash_entry_t *)conversation_get_proto_data(conversation, proto_rlogin);
395 if (!hash_info)
397 /* Populate new data struct... */
398 hash_info = wmem_new(wmem_file_scope(), rlogin_hash_entry_t);
399 hash_info->state = NONE;
400 hash_info->info_framenum = 0; /* no frame has the number 0 */
401 hash_info->user_name[0] = '\0';
403 /* ... and store in conversation */
404 conversation_add_proto_data(conversation, proto_rlogin, hash_info);
407 /* Set protocol column text */
408 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Rlogin");
410 /* Set info column */
411 /* Show user-name if available */
412 if (hash_info->user_name[0])
414 col_add_fstr(pinfo->cinfo, COL_INFO,
415 "User name: %s, ", hash_info->user_name);
417 else
419 col_clear(pinfo->cinfo, COL_INFO);
422 /* Work out packet content summary for display */
423 length = tvb_length(tvb);
424 if (length != 0)
426 /* Initial NULL byte represents part of connection handshake */
427 if (tvb_get_guint8(tvb, 0) == '\0')
429 col_append_str(pinfo->cinfo, COL_INFO,
430 (pinfo->destport == RLOGIN_PORT) ?
431 "Start Handshake" :
432 "Startup info received");
434 else
435 if (tcpinfo->urgent && length >= tcpinfo->urgent_pointer)
437 /* Urgent pointer inside current data represents a control message */
438 col_append_str(pinfo->cinfo, COL_INFO, "Control Message");
440 else
442 /* Search for 2 consecutive ff bytes
443 (signifies window change control message) */
444 ti_offset = tvb_find_guint8(tvb, 0, -1, 0xff);
445 if (ti_offset != -1 &&
446 tvb_bytes_exist(tvb, ti_offset + 1, 1) &&
447 tvb_get_guint8(tvb, ti_offset + 1) == 0xff)
449 col_append_str(pinfo->cinfo, COL_INFO, "Terminal Info");
451 else
453 /* Show any text data in the frame */
454 int bytes_to_copy = tvb_length(tvb);
455 if (bytes_to_copy > 128)
457 /* Truncate to 128 bytes for display */
458 bytes_to_copy = 128;
461 /* Add data into info column */
462 col_append_fstr(pinfo->cinfo, COL_INFO,
463 "Data: %s",
464 tvb_format_text(tvb, 0, bytes_to_copy));
469 /* See if conversation state needs to be updated */
470 rlogin_state_machine(hash_info, tvb, pinfo);
472 /* Dissect in detail */
473 rlogin_display(hash_info, tvb, pinfo, tree, tcpinfo);
475 return tvb_length(tvb);
479 void proto_register_rlogin(void)
481 static gint *ett[] = {
482 &ett_rlogin,
483 &ett_rlogin_window,
484 &ett_rlogin_window_rows,
485 &ett_rlogin_window_cols,
486 &ett_rlogin_window_x_pixels,
487 &ett_rlogin_window_y_pixels,
488 &ett_rlogin_user_info
491 static hf_register_info hf[] =
493 { &hf_user_info,
494 { "User Info", "rlogin.user_info", FT_STRING, BASE_NONE,
495 NULL, 0x0, NULL, HFILL
498 { &hf_client_startup_flag,
499 { "Client startup flag", "rlogin.client_startup_flag", FT_UINT8, BASE_HEX,
500 NULL, 0x0, NULL, HFILL
503 { &hf_startup_info_received_flag,
504 { "Startup info received flag", "rlogin.startup_info_received_flag", FT_UINT8, BASE_HEX,
505 NULL, 0x0, NULL, HFILL
508 { &hf_user_info_client_user_name,
509 { "Client-user-name", "rlogin.client_user_name", FT_STRING, BASE_NONE,
510 NULL, 0x0, NULL, HFILL
513 { &hf_user_info_server_user_name,
514 { "Server-user-name", "rlogin.server_user_name", FT_STRING, BASE_NONE,
515 NULL, 0x0, NULL, HFILL
518 { &hf_user_info_terminal_type,
519 { "Terminal-type", "rlogin.terminal_type", FT_STRING, BASE_NONE,
520 NULL, 0x0, NULL, HFILL
523 { &hf_user_info_terminal_speed,
524 { "Terminal-speed", "rlogin.terminal_speed", FT_UINT32, BASE_DEC,
525 NULL, 0x0, NULL, HFILL
528 { &hf_control_message,
529 { "Control message", "rlogin.control_message", FT_UINT8, BASE_HEX,
530 VALS(control_message_vals), 0x0, NULL, HFILL
533 { &hf_window_info,
534 { "Window Info", "rlogin.window_size", FT_NONE, BASE_NONE,
535 NULL, 0x0, NULL, HFILL
538 { &hf_window_info_ss,
539 { "Window size marker", "rlogin.window_size.ss", FT_STRING, BASE_NONE,
540 NULL, 0x0, NULL, HFILL
543 { &hf_window_info_rows,
544 { "Rows", "rlogin.window_size.rows", FT_UINT16, BASE_DEC,
545 NULL, 0x0, NULL, HFILL
548 { &hf_window_info_cols,
549 { "Columns", "rlogin.window_size.cols", FT_UINT16, BASE_DEC,
550 NULL, 0x0, NULL, HFILL
553 { &hf_window_info_x_pixels,
554 { "X Pixels", "rlogin.window_size.x_pixels", FT_UINT16, BASE_DEC,
555 NULL, 0x0, NULL, HFILL
558 { &hf_window_info_y_pixels,
559 { "Y Pixels", "rlogin.window_size.y_pixels", FT_UINT16, BASE_DEC,
560 NULL, 0x0, NULL, HFILL
563 { &hf_data,
564 { "Data", "rlogin.data", FT_STRING, BASE_NONE,
565 NULL, 0x0, NULL, HFILL
570 proto_rlogin = proto_register_protocol("Rlogin Protocol", "Rlogin", "rlogin");
572 proto_register_field_array(proto_rlogin, hf, array_length(hf));
573 proto_register_subtree_array(ett, array_length(ett));
576 void proto_reg_handoff_rlogin(void)
578 /* Dissector install routine */
579 dissector_handle_t rlogin_handle = new_create_dissector_handle(dissect_rlogin,proto_rlogin);
580 dissector_add_uint("tcp.port", RLOGIN_PORT, rlogin_handle);