Replace the types from sys/types.h and netinet/in.h by their glib.h
[obnox/wireshark/wip.git] / packet-rlogin.c
1 /* packet-rlogin.c
2  * Routines for unix rlogin packet dissection
3  * Copyright 2000, Jeffrey C. Foster <jfoste@woodward.com>
4  *
5  * $Id: packet-rlogin.c,v 1.27 2002/08/02 23:35:57 jmayer Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * Based upon RFC-1282 - BSD Rlogin
12  * 
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.
17  * 
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.
22  * 
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.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <glib.h>
35
36 #include <epan/packet.h>
37 #include <epan/conversation.h>
38
39 #include "packet-tcp.h"
40
41 #define TCP_PORT_RLOGIN 513
42
43 static int proto_rlogin = -1;
44
45 static int ett_rlogin = -1;
46 static int ett_rlogin_window = -1;
47 static int ett_rlogin_user_info = -1;
48 static int ett_rlogin_window_rows = -1;
49 static int ett_rlogin_window_cols = -1;
50 static int ett_rlogin_window_x_pixels = -1;
51 static int ett_rlogin_window_y_pixels = -1;
52
53 static int hf_user_info = -1;
54 static int hf_window_info = -1;
55 static int hf_window_info_rows = -1;
56 static int hf_window_info_cols = -1;
57 static int hf_window_info_x_pixels = -1;
58 static int hf_window_info_y_pixels = -1;
59
60 #define RLOGIN_PORT 513
61
62 #define NAME_LEN 32
63
64 typedef struct {
65         int     state;
66         guint32 info_framenum;
67         char    name[ NAME_LEN];
68         
69 } rlogin_hash_entry_t;
70
71 #define NONE            0
72 #define USER_INFO_WAIT  1
73 #define DONE            2
74 #define BAD             2
75
76 static GMemChunk *rlogin_vals = NULL;
77
78 #define rlogin_hash_init_count 20
79
80 static guint32 last_abs_sec = 0;
81 static guint32 last_abs_usec= 0;
82
83 static void
84 rlogin_init(void)
85 {
86
87 /* Routine to initialize rlogin protocol before each capture or filter pass. */
88 /* Release any memory if needed.  Then setup the memory chunks.         */
89
90         last_abs_sec = 0;
91         last_abs_usec= 0;
92
93         if (rlogin_vals)
94                 g_mem_chunk_destroy(rlogin_vals);
95
96         rlogin_vals = g_mem_chunk_new("rlogin_vals",
97                 sizeof( rlogin_hash_entry_t),
98                 rlogin_hash_init_count * sizeof( rlogin_hash_entry_t),
99                 G_ALLOC_AND_FREE);
100 }
101
102
103 /**************** Decoder State Machine ******************/
104
105 static void  
106 rlogin_state_machine( rlogin_hash_entry_t *hash_info, tvbuff_t *tvb,
107         packet_info *pinfo)
108 {
109         guint length;
110         gint stringlen;
111
112 /* rlogin stream decoder */
113 /* Just watched for second packet from client with the user name and    */
114 /* terminal type information.                                           */
115
116
117         if ( pinfo->destport != RLOGIN_PORT)   /* not from client */
118                 return;
119                                                 /* exit if not needed */
120         if (( hash_info->state == DONE) || (  hash_info->state == BAD))
121                 return;
122                 
123                                                 /* test timestamp */
124         if (( last_abs_sec > pinfo->fd->abs_secs) || 
125             (( last_abs_sec == pinfo->fd->abs_secs) &&
126              ( last_abs_usec >= pinfo->fd->abs_usecs)))
127                 return;
128
129         last_abs_sec = pinfo->fd->abs_secs;             /* save timestamp */
130         last_abs_usec = pinfo->fd->abs_usecs;
131
132         length = tvb_length(tvb);
133         if ( length == 0)                               /* exit if no data */
134                 return;   
135
136         if ( hash_info->state == NONE){                 /* new connection*/
137                 if (tvb_get_guint8(tvb, 0) != '\0') {
138                         /*
139                          * We expected a NUL, but didn't get one; quit.
140                          */
141                         hash_info->state = DONE;
142                         return;
143                 }
144                 else {
145                         if (length <= 1)                /* if no data   */
146                                 hash_info->state = USER_INFO_WAIT;
147                         else {
148                                 hash_info->state = DONE;
149                                 hash_info->info_framenum = pinfo->fd->num;
150                         }       
151                 }
152         }                                       /* expect user data here */
153 /*$$$ may need to do more checking here */      
154         else if ( hash_info->state == USER_INFO_WAIT) {
155                 hash_info->state = DONE;        
156                 hash_info->info_framenum = pinfo->fd->num;
157                                                         /* save name for later*/
158                 stringlen = tvb_strnlen(tvb, 0, NAME_LEN);
159                 if (stringlen == -1)
160                         stringlen = NAME_LEN - 1;       /* no '\0' found */
161                 else if (stringlen > NAME_LEN - 1)
162                         stringlen = NAME_LEN - 1;       /* name too long */
163                 tvb_memcpy(tvb, (guint8 *)hash_info->name, 0, stringlen);
164                 hash_info->name[stringlen] = '\0';
165                 
166                 if (check_col(pinfo->cinfo, COL_INFO))  /* update summary */
167                         col_append_str(pinfo->cinfo, COL_INFO,
168                             ", User information");
169         }               
170 }
171
172 static void rlogin_display( rlogin_hash_entry_t *hash_info, tvbuff_t *tvb,
173         packet_info *pinfo, proto_tree *tree, struct tcpinfo *tcpinfo)
174 {
175 /* Display the proto tree */
176         int             offset = 0;
177         proto_tree      *rlogin_tree, *user_info_tree, *window_tree;
178         proto_item      *ti;
179         guint           length;
180         int             str_len;
181         gint            ti_offset;
182         proto_item      *user_info_item,  *window_info_item;
183
184         ti = proto_tree_add_item( tree, proto_rlogin, tvb, 0, -1, FALSE);
185
186         rlogin_tree = proto_item_add_subtree(ti, ett_rlogin);
187
188         length = tvb_length(tvb);
189         if ( length == 0)                       /* exit if no captured data */
190                 return;
191
192         /*
193          * XXX - this works only if the urgent pointer points to something
194          * in this segment; to make it work if the urgent pointer points
195          * to something past this segment, we'd have to remember the urgent
196          * pointer setting for this conversation.
197          */
198         if ( tcpinfo->urgent &&                 /* if urgent pointer set */
199              length >= tcpinfo->urgent_pointer) {       /* and it's in this frame */
200
201                 int urgent_offset = tcpinfo->urgent_pointer - 1;
202                 guint8 Temp = tvb_get_guint8(tvb, urgent_offset);
203                 
204                 if (urgent_offset > offset)     /* check for data in front */
205                         proto_tree_add_text( rlogin_tree, tvb, offset,
206                             urgent_offset, "Data");
207                 
208                 proto_tree_add_text( rlogin_tree, tvb, urgent_offset, 1,
209                                 "Control byte: %u (%s)",
210                                 Temp,
211                                 (Temp == 0x02) ? "Clear buffer" :
212                                 (Temp == 0x10) ? "Raw mode" :
213                                 (Temp == 0x20) ? "Cooked mode" :
214                                 (Temp == 0x80) ? "Window size request" :
215                                 "Unknown");
216                 offset = urgent_offset + 1;     /* adjust offset */
217         }
218         else if ( tvb_get_guint8(tvb, offset) == '\0'){   /* startup */
219                 if ( pinfo->srcport== RLOGIN_PORT)   /* from server */
220                         proto_tree_add_text(rlogin_tree, tvb, offset, 1,
221                                         "Startup info received flag (0x00)");
222                                         
223                 else 
224                         proto_tree_add_text(rlogin_tree, tvb, offset, 1,
225                                         "Client Startup Flag (0x00)");
226                 ++offset;
227         }
228                 
229         if (!tvb_offset_exists(tvb, offset))
230                 return; /* No more data to check */
231
232         if ( hash_info->info_framenum == pinfo->fd->num){
233                 /*
234                  * First frame of conversation, hence user info?
235                  */
236                 user_info_item = proto_tree_add_item( rlogin_tree, hf_user_info, tvb,
237                         offset, -1, FALSE);
238
239                 /*
240                  * Do server user name.
241                  */
242                 str_len = tvb_strsize(tvb, offset);
243                 user_info_tree = proto_item_add_subtree( user_info_item,
244                         ett_rlogin_user_info);
245                 proto_tree_add_text(user_info_tree, tvb, offset, str_len,
246                                 "Server User Name: %.*s", str_len - 1,
247                                 tvb_get_ptr(tvb, offset, str_len - 1));
248                 offset += str_len;
249
250                 /*
251                  * Do client user name.
252                  */
253                 str_len = tvb_strsize(tvb, offset);
254                 proto_tree_add_text(user_info_tree, tvb, offset, str_len,
255                                 "Client User Name: %.*s", str_len - 1,
256                                 tvb_get_ptr(tvb, offset, str_len - 1));
257                 offset += str_len;
258                 
259                 /*
260                  * Do terminal type/speed.
261                  */
262                 str_len = tvb_strsize(tvb, offset);
263                 proto_tree_add_text(user_info_tree, tvb, offset, str_len,
264                                 "Terminal Type/Speed: %.*s", str_len - 1,
265                                 tvb_get_ptr(tvb, offset, str_len - 1));
266                 offset += str_len;
267         }
268
269         if (!tvb_offset_exists(tvb, offset))
270                 return; /* No more data to check */
271
272 /* test for terminal information, the data will have 2 0xff bytes */
273
274                                                 /* look for first 0xff byte */
275         ti_offset = tvb_find_guint8(tvb, offset, -1, 0xff);
276                 
277         if (ti_offset != -1 &&
278             tvb_bytes_exist(tvb, ti_offset + 1, 1) &&
279             tvb_get_guint8(tvb, ti_offset + 1) == 0xff) {
280                 /*
281                  * Found terminal info.
282                  */
283                 if (ti_offset > offset) {
284                         /*
285                          * There's data before the terminal info.
286                          */
287                         proto_tree_add_text( rlogin_tree, tvb, offset,
288                                 (ti_offset - offset), "Data");
289                         offset = ti_offset;
290                 }
291
292                 window_info_item = proto_tree_add_item(rlogin_tree,
293                                 hf_window_info, tvb, offset, 12, FALSE );
294                         
295                 window_tree = proto_item_add_subtree(window_info_item,
296                                          ett_rlogin_window);
297
298                 proto_tree_add_text(window_tree, tvb, offset, 2, 
299                         "Magic Cookie: (0xff, 0xff)");
300                 offset += 2;
301                                         
302                 proto_tree_add_text(window_tree, tvb, offset, 2, 
303                         "Window size marker: 'ss'");
304                 offset += 2;
305
306                 proto_tree_add_item(window_tree, hf_window_info_rows, tvb,
307                         offset, 2, FALSE);
308                 offset += 2;
309
310                 proto_tree_add_item(window_tree, hf_window_info_cols, tvb,
311                         offset, 2, FALSE);
312                 offset += 2;
313
314                 proto_tree_add_item(window_tree, hf_window_info_x_pixels, tvb,
315                         offset, 2, FALSE);
316                 offset += 2;
317
318                 proto_tree_add_item(window_tree, hf_window_info_y_pixels, tvb,
319                         offset, 2, FALSE);
320                 offset += 2;
321         }
322                         
323         if (tvb_offset_exists(tvb, offset)) {
324                 /*
325                  * There's more data in the frame.
326                  */
327                 proto_tree_add_text(rlogin_tree, tvb, offset, -1, "Data");
328         }
329 }       
330
331 static void
332 dissect_rlogin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
333 {
334         struct tcpinfo *tcpinfo = pinfo->private_data;
335         conversation_t *conversation;
336         rlogin_hash_entry_t *hash_info;
337         guint length;
338         gint ti_offset;
339
340                                                 /* Lookup this connection*/
341         conversation = find_conversation( &pinfo->src, &pinfo->dst,
342                 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
343
344         if ( !conversation) {
345                 conversation = conversation_new( &pinfo->src, &pinfo->dst,
346                         pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
347         }
348         hash_info = conversation_get_proto_data(conversation, proto_rlogin);
349         if ( !hash_info) {
350                 hash_info = g_mem_chunk_alloc(rlogin_vals);
351                 hash_info->state = NONE;
352                 hash_info->info_framenum = 0;   /* no frame has the number 0 */
353                 hash_info->name[ 0] = 0;
354                 conversation_add_proto_data(conversation, proto_rlogin,
355                         hash_info);
356         }
357         
358         if (check_col(pinfo->cinfo, COL_PROTOCOL))              /* update protocol  */
359                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Rlogin");
360
361         if (check_col(pinfo->cinfo, COL_INFO)){         /* display packet info*/
362
363                 char temp[1000];
364                 
365                 col_clear(pinfo->cinfo, COL_INFO);
366                 if ( hash_info->name[0]) {
367                         strcpy( temp, "User name: ");
368                         strcat( temp, hash_info->name);
369                         strcat( temp, ", ");
370                 }
371                 else 
372                         temp[0] = 0;
373
374                 length = tvb_length(tvb);
375                 if (length != 0) {
376                         if ( tvb_get_guint8(tvb, 0) == '\0')
377                                 strcat( temp, "Start Handshake"); 
378                         else if ( tcpinfo->urgent &&
379                                   length >= tcpinfo->urgent_pointer )
380                                 strcat( temp, "Control Message"); 
381
382                         else {                  /* check for terminal info */
383                                 ti_offset = tvb_find_guint8(tvb, 0, -1, 0xff);
384                                 if (ti_offset != -1 &&
385                                     tvb_bytes_exist(tvb, ti_offset + 1, 1) &&
386                                     tvb_get_guint8(tvb, ti_offset + 1) == 0xff)
387                                         strcat( temp, "Terminal Info");
388                                 else {
389                                         int i;
390                                         int bytes_to_copy;
391
392                                         strcat( temp, "Data: ");
393                                         i = strlen( temp);
394                                         bytes_to_copy = tvb_length(tvb);
395                                         if (bytes_to_copy > 128)
396                                                 bytes_to_copy = 128;
397                                         tvb_memcpy(tvb, (guint8 *)&temp[i], 0,
398                                             bytes_to_copy);
399                                         temp[i + bytes_to_copy] = '\0';
400                                 }
401                         }
402                 }               
403
404                 col_add_str(pinfo->cinfo, COL_INFO, temp);
405         }
406
407         rlogin_state_machine( hash_info, tvb, pinfo);
408
409         if ( tree)                              /* if proto tree, decode data */
410                 rlogin_display( hash_info, tvb, pinfo, tree, tcpinfo);
411 }
412
413
414 void
415 proto_register_rlogin( void){
416
417 /* Prep the rlogin protocol, for now, just register it  */
418
419         static gint *ett[] = {
420                 &ett_rlogin,
421                 &ett_rlogin_window,
422                 &ett_rlogin_window_rows,
423                 &ett_rlogin_window_cols,
424                 &ett_rlogin_window_x_pixels,
425                 &ett_rlogin_window_y_pixels,
426                 &ett_rlogin_user_info
427         };
428         
429         static hf_register_info hf[] = {
430
431                 { &hf_user_info,
432                         { "User Info", "rlogin.user_info", FT_NONE, BASE_NONE,
433                                  NULL, 0x0, "", HFILL
434                         }
435                 },
436                 { &hf_window_info,
437                         { "Window Info", "rlogin.window_size", FT_NONE, BASE_NONE,
438                                  NULL, 0x0, "", HFILL
439                         }
440                 },
441                 { &hf_window_info_rows,
442                         { "Rows", "rlogin.window_size.rows", FT_UINT16, BASE_DEC,
443                                  NULL, 0x0, "", HFILL
444                         }
445                 },
446                 { &hf_window_info_cols,
447                         { "Columns", "rlogin.window_size.cols", FT_UINT16, BASE_DEC,
448                                  NULL, 0x0, "", HFILL
449                         }
450                 },
451                 { &hf_window_info_x_pixels,
452                         { "X Pixels", "rlogin.window_size.x_pixels", FT_UINT16, BASE_DEC,
453                                  NULL, 0x0, "", HFILL
454                         }
455                 },
456                 { &hf_window_info_y_pixels,
457                         { "Y Pixels", "rlogin.window_size.y_pixels", FT_UINT16, BASE_DEC,
458                                  NULL, 0x0, "", HFILL
459                         }
460                 }
461         };
462
463         proto_rlogin = proto_register_protocol (
464                 "Rlogin Protocol", "Rlogin", "rlogin");
465
466         proto_register_field_array(proto_rlogin, hf, array_length(hf));
467         proto_register_subtree_array(ett, array_length(ett));  
468
469         register_init_routine( &rlogin_init);   /* register re-init routine */
470 }
471
472 void
473 proto_reg_handoff_rlogin(void) {
474
475         /* dissector install routine */ 
476  
477         dissector_handle_t rlogin_handle;
478
479         rlogin_handle = create_dissector_handle(dissect_rlogin, proto_rlogin);
480         dissector_add("tcp.port", TCP_PORT_RLOGIN, rlogin_handle);
481 }