2 * Routines for unix rlogin packet dissection
3 * Copyright 2000, Jeffrey C. Foster <jfoste@woodward.com>
5 * $Id: packet-rlogin.c,v 1.12 2001/01/03 06:55:31 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@zing.org>
9 * Copyright 1998 Gerald Combs
12 * Based upon RFC-1282 - BSD Rlogin
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
40 #ifdef HAVE_SYS_TYPES_H
41 # include <sys/types.h>
44 #ifdef HAVE_NETINET_IN_H
45 # include <netinet/in.h>
52 #ifdef NEED_SNPRINTF_H
53 # include "snprintf.h"
59 #include "alignment.h"
60 #include "conversation.h"
62 #include "packet-tcp.h"
65 #define CHECK_PACKET_LENGTH(X) if (!BYTES_ARE_IN_FRAME(offset, X)){ \
66 proto_tree_add_text(tree, NullTVB, offset, 0, "*** FRAME TOO SHORT ***"); \
70 #define TCP_PORT_RLOGIN 513
72 static int proto_rlogin = -1;
74 static int ett_rlogin = -1;
75 static int ett_rlogin_window = -1;
76 static int ett_rlogin_user_info = -1;
77 static int ett_rlogin_window_rows = -1;
78 static int ett_rlogin_window_cols = -1;
79 static int ett_rlogin_window_x_pixels = -1;
80 static int ett_rlogin_window_y_pixels = -1;
83 static int hf_user_info = -1;
84 static int hf_window_info = -1;
85 static int hf_window_info_rows = -1;
86 static int hf_window_info_cols = -1;
87 static int hf_window_info_x_pixels = -1;
88 static int hf_window_info_y_pixels = -1;
91 #define RLOGIN_PORT 513
100 }rlogin_hash_entry_t;
104 #define USER_INFO_WAIT 1
109 static GMemChunk *rlogin_vals = NULL;
111 #define rlogin_hash_init_count 20
113 static guint32 last_abs_sec = 0;
114 static guint32 last_abs_usec= 0;
116 /* Find the length of a '\0'-terminated string, *INCLUDING* the terminating
117 '\0', but don't run past the end of the packet doing so. */
119 string_len(const char *str, int maxlen)
123 str_end = memchr(str, '\0', maxlen);
124 if (str_end == NULL) {
125 /* No '\0' found - return the length as of when we stopped,
126 plus one to force the length to be too long and and
127 CHECK_PACKET_LENGTH to fail. */
130 return str_end - str + 1;
136 /* Routine to initialize rlogin protocol before each capture or filter pass. */
137 /* Release any memory if needed. Then setup the memory chunks. */
143 g_mem_chunk_destroy(rlogin_vals);
145 rlogin_vals = g_mem_chunk_new("rlogin_vals",
146 sizeof( rlogin_hash_entry_t),
147 rlogin_hash_init_count * sizeof( rlogin_hash_entry_t),
152 /**************** Decoder State Machine ******************/
155 rlogin_state_machine( rlogin_hash_entry_t *hash_info, const u_char *pd,
156 int offset, frame_data *fd) {
158 /* rlogin stream decoder */
159 /* Just watched for second packet from client with the user name and */
160 /* terminal type information. */
163 if ( pi.destport != RLOGIN_PORT) /* not from client */
165 /* exit if not needed */
166 if (( hash_info->state == DONE) || ( hash_info->state == BAD))
170 if (( last_abs_sec > fd->abs_secs) ||
171 (( last_abs_sec == fd->abs_secs) && ( last_abs_usec >= fd->abs_usecs)))
174 last_abs_sec = fd->abs_secs; /* save timestamp */
175 last_abs_usec = fd->abs_usecs;
177 if ( !IS_DATA_IN_FRAME(offset)) /* exit if no data */
180 if ( hash_info->state == NONE){ /* new connection*/
182 if ( GBYTE( pd, offset + 1)) { /* expect a NULL */
183 hash_info->state = DONE; /* quit, no NULL */
187 if (( END_OF_FRAME) <= 1) /* if no data */
188 hash_info->state = USER_INFO_WAIT;
190 hash_info->state = DONE;
191 hash_info->info_framenum = fd->num;
194 } /* expect user data here */
195 /*$$$ may need to do more checking here */
196 else if ( hash_info->state == USER_INFO_WAIT) {
197 hash_info->state = DONE;
198 hash_info->info_framenum = fd->num;
199 /* save name for later*/
200 strncpy( hash_info->name, &pd[ offset], NAME_LEN);
202 hash_info->name[ NAME_LEN] = 0;
204 if (check_col(fd, COL_INFO)) /* update summary */
205 col_append_str( fd, COL_INFO, ", User information");
211 static void rlogin_display( rlogin_hash_entry_t *hash_info, const u_char *pd,
212 int offset, frame_data *fd, proto_tree *tree) {
214 /* Display the proto tree */
216 proto_tree *rlogin_tree, *user_info_tree, *window_tree;
221 proto_item *user_info_item, *window_info_item;
223 ti = proto_tree_add_item( tree, proto_rlogin, NullTVB, offset,
224 END_OF_FRAME, FALSE);
226 rlogin_tree = proto_item_add_subtree(ti, ett_rlogin);
228 if ( !IS_DATA_IN_FRAME(offset)) /* exit if no data */
231 if ( tcp_urgent_pointer && /* if control message */
232 BYTES_ARE_IN_FRAME(offset + tcp_urgent_pointer - 1, 1)) {
234 int i = offset + tcp_urgent_pointer - 1;
235 guint16 Temp = GBYTE( pd, i);
237 if ( i < offset) /* check for data in front */
238 proto_tree_add_text( rlogin_tree, NullTVB, offset, i - offset,
241 proto_tree_add_text( rlogin_tree, NullTVB, i, 1, "Control byte: %u (%s)",
243 (Temp == 2) ? "Clear buffer" :
244 (Temp == 0x10) ? "Raw mode" :
245 (Temp == 0x20) ? "Cooked mode" :
246 (Temp == 0x80) ? "Window size request" :
248 offset = i; /* adjust offset */
251 else if ( !GBYTE( pd, offset)){ /* startup */
252 if ( pi.srcport== RLOGIN_PORT) /* from server */
253 proto_tree_add_text(rlogin_tree, NullTVB, offset, 1,
254 "Startup info received flag (0x00)");
257 proto_tree_add_text(rlogin_tree, NullTVB, offset, 1,
258 "Client Startup Flag (0x00)");
262 if (!IS_DATA_IN_FRAME(offset))
263 return; /* No more data to check */
265 if ( hash_info->info_framenum == fd->num){ /* user info ?*/
266 user_info_item = proto_tree_add_item( rlogin_tree, hf_user_info, NullTVB,
267 offset, END_OF_FRAME, FALSE);
269 str = &pd[ offset]; /* do server user name */
270 str_len = string_len( str, END_OF_FRAME);
271 CHECK_PACKET_LENGTH( str_len);
272 user_info_tree = proto_item_add_subtree( user_info_item,
273 ett_rlogin_user_info);
274 proto_tree_add_text( user_info_tree, NullTVB, offset, str_len,
275 "Server User Name: %.*s", str_len, str);
278 if (!IS_DATA_IN_FRAME(offset))
279 return; /* No more data to check */
280 str = &pd[ offset]; /* do client user name */
281 str_len = string_len( str, END_OF_FRAME);
282 CHECK_PACKET_LENGTH( str_len);
283 proto_tree_add_text( user_info_tree, NullTVB, offset, str_len,
284 "Client User Name: %.*s", str_len, str);
287 if (!IS_DATA_IN_FRAME(offset))
288 return; /* No more data to check */
289 str = &pd[ offset]; /* do terminal type/speed */
290 str_len = string_len( str, END_OF_FRAME);
291 CHECK_PACKET_LENGTH( str_len);
292 proto_tree_add_text( user_info_tree, NullTVB, offset, str_len,
293 "Terminal Type/Speed: %.*s", str_len, str);
297 if (!IS_DATA_IN_FRAME(offset))
298 return; /* No more data to check */
300 /* test for terminal information, the data will have 2 0xff bytes */
302 /* look for first 0xff byte */
303 Ptr = (guint8*)memchr( &pd[ offset], 0xff, END_OF_FRAME);
305 if (( Ptr) && (*(Ptr + 1) == 0xff)) { /* found terminal info */
307 int ti_offset = Ptr - pd; /* get offset */
309 if ( ti_offset < offset){ /*if data before terminal info*/
310 proto_tree_add_text( rlogin_tree, NullTVB, offset,
311 (ti_offset - offset), "Data");
315 CHECK_PACKET_LENGTH( 12);
316 window_info_item = proto_tree_add_item( rlogin_tree,
317 hf_window_info, NullTVB, offset, 12, FALSE );
319 window_tree = proto_item_add_subtree( window_info_item,
322 CHECK_PACKET_LENGTH( 2);
323 proto_tree_add_text( window_tree, NullTVB, offset, 2,
324 "Magic Cookie: (0xff, 0xff)");
327 CHECK_PACKET_LENGTH( 2);
328 proto_tree_add_text( window_tree, NullTVB, offset, 2,
329 "Window size marker: 'ss'");
332 CHECK_PACKET_LENGTH( 2);
333 proto_tree_add_uint( window_tree, hf_window_info_rows, NullTVB, offset,
334 2, pntohs( &pd[offset]));
337 CHECK_PACKET_LENGTH( 2);
338 proto_tree_add_uint( window_tree, hf_window_info_cols, NullTVB, offset,
339 2, pntohs( &pd[offset]) );
342 CHECK_PACKET_LENGTH( 2);
343 proto_tree_add_uint( window_tree, hf_window_info_x_pixels, NullTVB,
344 offset, 2, pntohs( &pd[offset]));
347 CHECK_PACKET_LENGTH( 2);
348 proto_tree_add_uint( window_tree, hf_window_info_y_pixels, NullTVB,
349 offset, 2, pntohs( &pd[offset]) );
353 if ( END_OF_FRAME != 0) /* if more data */
354 proto_tree_add_text(rlogin_tree, NullTVB, offset, END_OF_FRAME, "Data");
361 dissect_rlogin(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
365 rlogin_hash_entry_t *hash_info = 0;
366 conversation_t *conversation;
368 OLD_CHECK_DISPLAY_AS_DATA(proto_rlogin, pd, offset, fd, tree);
370 /* Lookup this connection*/
371 conversation = find_conversation( &pi.src, &pi.dst, pi.ptype,
372 pi.srcport, pi.destport, 0);
374 if ( conversation) /* conversation found */
375 hash_info = conversation->data;
377 /* new conversation create local data structure */
379 hash_info = g_mem_chunk_alloc(rlogin_vals);
380 hash_info->state = NONE;
381 hash_info->info_framenum = -1;
382 hash_info->name[ 0] = 0;
384 conversation_new( &pi.src, &pi.dst, pi.ptype,
385 pi.srcport, pi.destport, hash_info, 0);
388 if (check_col(fd, COL_PROTOCOL)) /* update protocol */
389 col_set_str(fd, COL_PROTOCOL, "Rlogin");
391 if (check_col(fd, COL_INFO)){ /* display packet info*/
395 if ( hash_info->name[0]) {
396 strcpy( temp, "User name: ");
397 strcat( temp, hash_info->name);
403 if ( !GBYTE(pd, offset))
404 strcat( temp, "Start Handshake");
405 else if ( tcp_urgent_pointer)
406 strcat( temp, "Control Message");
408 else { /* check for terminal info */
409 Ptr = (guint8*)memchr( &pd[ offset], 0xff, END_OF_FRAME);
411 if (( Ptr) && (*(Ptr + 1) == 0xff))
412 strcat( temp, "Terminal Info");
415 strcat( temp, "Data:");
417 strncat( temp, &pd[ offset], 128);
418 temp[ i + MIN( 128, END_OF_FRAME)] = 0;
422 col_add_str(fd, COL_INFO, temp);
425 rlogin_state_machine( hash_info, pd, offset, fd);
427 if ( tree) /* if proto tree, decode data */
428 rlogin_display( hash_info, pd, offset, fd, tree);
433 proto_register_rlogin( void){
435 /* Prep the rlogin protocol, for now, just register it */
437 static gint *ett[] = {
440 &ett_rlogin_window_rows,
441 &ett_rlogin_window_cols,
442 &ett_rlogin_window_x_pixels,
443 &ett_rlogin_window_y_pixels,
444 &ett_rlogin_user_info
447 static hf_register_info hf[] = {
450 { "User Info", "rlogin.user_info", FT_NONE, BASE_NONE,
455 { "Window Info", "rlogin.window_size", FT_NONE, BASE_NONE,
459 { &hf_window_info_rows,
460 { "Rows", "rlogin.window_size.rows", FT_UINT16, BASE_DEC,
464 { &hf_window_info_cols,
465 { "Columns", "rlogin.window_size.cols", FT_UINT16, BASE_DEC,
469 { &hf_window_info_x_pixels,
470 { "X Pixels", "rlogin.window_size.x_pixels", FT_UINT16, BASE_DEC,
474 { &hf_window_info_y_pixels,
475 { "Y Pixels", "rlogin.window_size.y_pixels", FT_UINT16, BASE_DEC,
482 proto_rlogin = proto_register_protocol (
483 "Rlogin Protocol", "Rlogin", "rlogin");
485 proto_register_field_array(proto_rlogin, hf, array_length(hf));
486 proto_register_subtree_array(ett, array_length(ett));
488 register_init_routine( &rlogin_init); /* register re-init routine */
494 proto_reg_handoff_rlogin(void) {
496 /* dissector install routine */
498 old_dissector_add("tcp.port", TCP_PORT_RLOGIN, dissect_rlogin);