2 * Routines for unix rlogin packet dissection
3 * Copyright 2000, Jeffrey C. Foster <jfoste@woodward.com>
5 * $Id: packet-rlogin.c,v 1.23 2001/12/03 03:59:38 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
36 #ifdef HAVE_NETINET_IN_H
37 # include <netinet/in.h>
45 #include "conversation.h"
47 #include "packet-tcp.h"
49 #define TCP_PORT_RLOGIN 513
51 static int proto_rlogin = -1;
53 static int ett_rlogin = -1;
54 static int ett_rlogin_window = -1;
55 static int ett_rlogin_user_info = -1;
56 static int ett_rlogin_window_rows = -1;
57 static int ett_rlogin_window_cols = -1;
58 static int ett_rlogin_window_x_pixels = -1;
59 static int ett_rlogin_window_y_pixels = -1;
61 static int hf_user_info = -1;
62 static int hf_window_info = -1;
63 static int hf_window_info_rows = -1;
64 static int hf_window_info_cols = -1;
65 static int hf_window_info_x_pixels = -1;
66 static int hf_window_info_y_pixels = -1;
68 #define RLOGIN_PORT 513
74 guint32 info_framenum;
77 } rlogin_hash_entry_t;
80 #define USER_INFO_WAIT 1
84 static GMemChunk *rlogin_vals = NULL;
86 #define rlogin_hash_init_count 20
88 static guint32 last_abs_sec = 0;
89 static guint32 last_abs_usec= 0;
95 /* Routine to initialize rlogin protocol before each capture or filter pass. */
96 /* Release any memory if needed. Then setup the memory chunks. */
102 g_mem_chunk_destroy(rlogin_vals);
104 rlogin_vals = g_mem_chunk_new("rlogin_vals",
105 sizeof( rlogin_hash_entry_t),
106 rlogin_hash_init_count * sizeof( rlogin_hash_entry_t),
111 /**************** Decoder State Machine ******************/
114 rlogin_state_machine( rlogin_hash_entry_t *hash_info, tvbuff_t *tvb,
120 /* rlogin stream decoder */
121 /* Just watched for second packet from client with the user name and */
122 /* terminal type information. */
125 if ( pinfo->destport != RLOGIN_PORT) /* not from client */
127 /* exit if not needed */
128 if (( hash_info->state == DONE) || ( hash_info->state == BAD))
132 if (( last_abs_sec > pinfo->fd->abs_secs) ||
133 (( last_abs_sec == pinfo->fd->abs_secs) &&
134 ( last_abs_usec >= pinfo->fd->abs_usecs)))
137 last_abs_sec = pinfo->fd->abs_secs; /* save timestamp */
138 last_abs_usec = pinfo->fd->abs_usecs;
140 length = tvb_length(tvb);
141 if ( length == 0) /* exit if no data */
144 if ( hash_info->state == NONE){ /* new connection*/
145 if (tvb_get_guint8(tvb, 0) != '\0') {
147 * We expected a NUL, but didn't get one; quit.
149 hash_info->state = DONE;
153 if (length <= 1) /* if no data */
154 hash_info->state = USER_INFO_WAIT;
156 hash_info->state = DONE;
157 hash_info->info_framenum = pinfo->fd->num;
160 } /* expect user data here */
161 /*$$$ may need to do more checking here */
162 else if ( hash_info->state == USER_INFO_WAIT) {
163 hash_info->state = DONE;
164 hash_info->info_framenum = pinfo->fd->num;
165 /* save name for later*/
166 stringlen = tvb_strnlen(tvb, 0, NAME_LEN);
168 stringlen = NAME_LEN - 1; /* no '\0' found */
169 else if (stringlen > NAME_LEN - 1)
170 stringlen = NAME_LEN - 1; /* name too long */
171 tvb_memcpy(tvb, (guint8 *)hash_info->name, 0, stringlen);
172 hash_info->name[stringlen] = '\0';
174 if (check_col(pinfo->fd, COL_INFO)) /* update summary */
175 col_append_str(pinfo->fd, COL_INFO,
176 ", User information");
180 static void rlogin_display( rlogin_hash_entry_t *hash_info, tvbuff_t *tvb,
181 packet_info *pinfo, proto_tree *tree, struct tcpinfo *tcpinfo)
183 /* Display the proto tree */
185 proto_tree *rlogin_tree, *user_info_tree, *window_tree;
190 proto_item *user_info_item, *window_info_item;
192 ti = proto_tree_add_item( tree, proto_rlogin, tvb, 0,
193 tvb_length(tvb), FALSE);
195 rlogin_tree = proto_item_add_subtree(ti, ett_rlogin);
197 length = tvb_length(tvb);
198 if ( length == 0) /* exit if no captured data */
202 * XXX - this works only if the urgent pointer points to something
203 * in this segment; to make it work if the urgent pointer points
204 * to something past this segment, we'd have to remember the urgent
205 * pointer setting for this conversation.
207 if ( tcpinfo->urgent && /* if urgent pointer set */
208 length >= tcpinfo->urgent_pointer) { /* and it's in this frame */
210 int urgent_offset = tcpinfo->urgent_pointer - 1;
211 guint8 Temp = tvb_get_guint8(tvb, urgent_offset);
213 if (urgent_offset > offset) /* check for data in front */
214 proto_tree_add_text( rlogin_tree, tvb, offset,
215 urgent_offset, "Data");
217 proto_tree_add_text( rlogin_tree, tvb, urgent_offset, 1,
218 "Control byte: %u (%s)",
220 (Temp == 0x02) ? "Clear buffer" :
221 (Temp == 0x10) ? "Raw mode" :
222 (Temp == 0x20) ? "Cooked mode" :
223 (Temp == 0x80) ? "Window size request" :
225 offset = urgent_offset + 1; /* adjust offset */
227 else if ( tvb_get_guint8(tvb, offset) == '\0'){ /* startup */
228 if ( pinfo->srcport== RLOGIN_PORT) /* from server */
229 proto_tree_add_text(rlogin_tree, tvb, offset, 1,
230 "Startup info received flag (0x00)");
233 proto_tree_add_text(rlogin_tree, tvb, offset, 1,
234 "Client Startup Flag (0x00)");
238 if (!tvb_offset_exists(tvb, offset))
239 return; /* No more data to check */
241 if ( hash_info->info_framenum == pinfo->fd->num){
243 * First frame of conversation, hence user info?
245 user_info_item = proto_tree_add_item( rlogin_tree, hf_user_info, tvb,
246 offset, tvb_length_remaining(tvb, offset), FALSE);
249 * Do server user name.
251 str_len = tvb_strsize(tvb, offset);
252 user_info_tree = proto_item_add_subtree( user_info_item,
253 ett_rlogin_user_info);
254 proto_tree_add_text(user_info_tree, tvb, offset, str_len,
255 "Server User Name: %.*s", str_len - 1,
256 tvb_get_ptr(tvb, offset, str_len - 1));
260 * Do client user name.
262 str_len = tvb_strsize(tvb, offset);
263 proto_tree_add_text(user_info_tree, tvb, offset, str_len,
264 "Client User Name: %.*s", str_len - 1,
265 tvb_get_ptr(tvb, offset, str_len - 1));
269 * Do terminal type/speed.
271 str_len = tvb_strsize(tvb, offset);
272 proto_tree_add_text(user_info_tree, tvb, offset, str_len,
273 "Terminal Type/Speed: %.*s", str_len - 1,
274 tvb_get_ptr(tvb, offset, str_len - 1));
278 if (!tvb_offset_exists(tvb, offset))
279 return; /* No more data to check */
281 /* test for terminal information, the data will have 2 0xff bytes */
283 /* look for first 0xff byte */
284 ti_offset = tvb_find_guint8(tvb, offset, -1, 0xff);
286 if (ti_offset != -1 &&
287 tvb_bytes_exist(tvb, ti_offset + 1, 1) &&
288 tvb_get_guint8(tvb, ti_offset + 1) == 0xff) {
290 * Found terminal info.
292 if (ti_offset > offset) {
294 * There's data before the terminal info.
296 proto_tree_add_text( rlogin_tree, tvb, offset,
297 (ti_offset - offset), "Data");
301 window_info_item = proto_tree_add_item(rlogin_tree,
302 hf_window_info, tvb, offset, 12, FALSE );
304 window_tree = proto_item_add_subtree(window_info_item,
307 proto_tree_add_text(window_tree, tvb, offset, 2,
308 "Magic Cookie: (0xff, 0xff)");
311 proto_tree_add_text(window_tree, tvb, offset, 2,
312 "Window size marker: 'ss'");
315 proto_tree_add_item(window_tree, hf_window_info_rows, tvb,
319 proto_tree_add_item(window_tree, hf_window_info_cols, tvb,
323 proto_tree_add_item(window_tree, hf_window_info_x_pixels, tvb,
327 proto_tree_add_item(window_tree, hf_window_info_y_pixels, tvb,
332 if (tvb_offset_exists(tvb, offset)) {
334 * There's more data in the frame.
336 proto_tree_add_text(rlogin_tree, tvb, offset,
337 tvb_length_remaining(tvb, offset), "Data");
342 dissect_rlogin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
344 struct tcpinfo *tcpinfo = pinfo->private_data;
345 conversation_t *conversation;
346 rlogin_hash_entry_t *hash_info;
350 /* Lookup this connection*/
351 conversation = find_conversation( &pinfo->src, &pinfo->dst,
352 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
354 if ( !conversation) {
355 conversation = conversation_new( &pinfo->src, &pinfo->dst,
356 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
358 hash_info = conversation_get_proto_data(conversation, proto_rlogin);
360 hash_info = g_mem_chunk_alloc(rlogin_vals);
361 hash_info->state = NONE;
362 hash_info->info_framenum = 0; /* no frame has the number 0 */
363 hash_info->name[ 0] = 0;
364 conversation_add_proto_data(conversation, proto_rlogin,
368 if (check_col(pinfo->fd, COL_PROTOCOL)) /* update protocol */
369 col_set_str(pinfo->fd, COL_PROTOCOL, "Rlogin");
371 if (check_col(pinfo->fd, COL_INFO)){ /* display packet info*/
375 col_clear(pinfo->fd, COL_INFO);
376 if ( hash_info->name[0]) {
377 strcpy( temp, "User name: ");
378 strcat( temp, hash_info->name);
384 length = tvb_length(tvb);
386 if ( tvb_get_guint8(tvb, 0) == '\0')
387 strcat( temp, "Start Handshake");
388 else if ( tcpinfo->urgent &&
389 length >= tcpinfo->urgent_pointer )
390 strcat( temp, "Control Message");
392 else { /* check for terminal info */
393 ti_offset = tvb_find_guint8(tvb, 0, -1, 0xff);
394 if (ti_offset != -1 &&
395 tvb_bytes_exist(tvb, ti_offset + 1, 1) &&
396 tvb_get_guint8(tvb, ti_offset + 1) == 0xff)
397 strcat( temp, "Terminal Info");
402 strcat( temp, "Data: ");
404 bytes_to_copy = tvb_length(tvb);
405 if (bytes_to_copy > 128)
407 tvb_memcpy(tvb, (guint8 *)&temp[i], 0,
409 temp[i + bytes_to_copy] = '\0';
414 col_add_str(pinfo->fd, COL_INFO, temp);
417 rlogin_state_machine( hash_info, tvb, pinfo);
419 if ( tree) /* if proto tree, decode data */
420 rlogin_display( hash_info, tvb, pinfo, tree, tcpinfo);
425 proto_register_rlogin( void){
427 /* Prep the rlogin protocol, for now, just register it */
429 static gint *ett[] = {
432 &ett_rlogin_window_rows,
433 &ett_rlogin_window_cols,
434 &ett_rlogin_window_x_pixels,
435 &ett_rlogin_window_y_pixels,
436 &ett_rlogin_user_info
439 static hf_register_info hf[] = {
442 { "User Info", "rlogin.user_info", FT_NONE, BASE_NONE,
447 { "Window Info", "rlogin.window_size", FT_NONE, BASE_NONE,
451 { &hf_window_info_rows,
452 { "Rows", "rlogin.window_size.rows", FT_UINT16, BASE_DEC,
456 { &hf_window_info_cols,
457 { "Columns", "rlogin.window_size.cols", FT_UINT16, BASE_DEC,
461 { &hf_window_info_x_pixels,
462 { "X Pixels", "rlogin.window_size.x_pixels", FT_UINT16, BASE_DEC,
466 { &hf_window_info_y_pixels,
467 { "Y Pixels", "rlogin.window_size.y_pixels", FT_UINT16, BASE_DEC,
473 proto_rlogin = proto_register_protocol (
474 "Rlogin Protocol", "Rlogin", "rlogin");
476 proto_register_field_array(proto_rlogin, hf, array_length(hf));
477 proto_register_subtree_array(ett, array_length(ett));
479 register_init_routine( &rlogin_init); /* register re-init routine */
483 proto_reg_handoff_rlogin(void) {
485 /* dissector install routine */
487 dissector_handle_t rlogin_handle;
489 rlogin_handle = create_dissector_handle(dissect_rlogin, proto_rlogin);
490 dissector_add("tcp.port", TCP_PORT_RLOGIN, rlogin_handle);