Don't use temporary buffers for strings; use the data in the packet
[obnox/wireshark/wip.git] / packet-telnet.c
1 /* packet-telnet.c
2  * Routines for telnet packet dissection
3  * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
4  *
5  * $Id: packet-telnet.c,v 1.9 2000/03/23 10:25:38 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-pop.c
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
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
36 #endif
37
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif
41
42 #include <string.h>
43 #include <glib.h>
44 #include "packet.h"
45
46 static int proto_telnet = -1;
47
48 static gint ett_telnet = -1;
49 static gint ett_telnet_subopt = -1;
50
51 /* Some defines for Telnet */
52
53 #define TN_IAC   255
54 #define TN_DONT  254
55 #define TN_DO    253
56 #define TN_WONT  252
57 #define TN_WILL  251
58 #define TN_SB    250
59 #define TN_GA    249
60 #define TN_EL    248
61 #define TN_EC    247
62 #define TN_AYT   246
63 #define TN_AO    245
64 #define TN_IP    244
65 #define TN_BRK   243
66 #define TN_DM    242
67 #define TN_NOP   241
68 #define TN_SE    240
69 #define TN_EOR   239
70 #define TN_ABORT 238
71 #define TN_SUSP  237
72 #define TN_EOF   236
73
74 static const char *options[] = {
75   "Binary Transmission",
76   "Echo",
77   "Reconnection",
78   "Suppress Go Ahead",
79   "Approx Message Size Negotiation",
80   "Status",
81   "Timing Mark",
82   "Remote Controlled Trans and Echo",
83   "Output Line Width",
84   "Output Page Size",
85   "Output Carriage-Return Disposition",
86   "Output Horizontal Tab Stops",
87   "Output Horizontal Tab Disposition",
88   "Output Formfeed Disposition",
89   "Output Vertical Tabstops",
90   "Output Vertical Tab Disposition",
91   "Output Linefeed Disposition",
92   "Extended ASCII",
93   "Logout",
94   "Byte Macro",
95   "Data Entry Terminal",
96   "SUPDUP",
97   "SUPDUP Output",
98   "Send Location",
99   "Terminal Type",
100   "End of Record",
101   "TACACS User Identification",
102   "Output Marking",
103   "Terminal Location Number",
104   "Telnet 3270 Regime",
105   "X.3 PAD",
106   "Negotiate About Window Size",
107   "Terminal Speed",
108   "Remote Flow Control",
109   "Linemode",
110   "X Display Location",
111   "Environment Option",
112   "Authentication Option",
113   "Encryption Option",
114   "New Environment Option",
115   "TN3270E"
116 };
117
118 #define NOPTIONS        (sizeof options / sizeof options[0])
119
120 static int
121 telnet_sub_option(proto_tree *telnet_tree, const u_char *pd,
122                 int start_offset)
123 {
124   proto_tree *ti, *option_tree;
125   int offset = start_offset;
126   int subneg_len, req;
127   gboolean not_found = TRUE;
128   const u_char *opt;
129
130   offset += 2;  /* skip IAC and SB */
131
132   /* Figure out the option and type */
133   if (pd[offset] > NOPTIONS)
134     opt = "<unknown option>";
135   else
136     opt = options[pd[offset]];
137   offset++;
138   req = pd[offset];
139   offset++;
140
141   while (offset < pi.captured_len && not_found) {  
142     if (pd[offset] == TN_IAC)
143       not_found = FALSE;
144     else
145       offset++;
146   }
147
148   subneg_len = offset - start_offset;
149
150   ti = proto_tree_add_text(telnet_tree, start_offset, subneg_len,
151                         "Suboption Begin: %s", opt);
152
153   option_tree = proto_item_add_subtree(ti, ett_telnet_subopt);
154
155   proto_tree_add_text(option_tree, start_offset + 2, 2,
156                         "%s %s", (req ? "Send your" : "Here's my"), opt);
157
158   if (req == 0) {  /* Add the value */
159     proto_tree_add_text(option_tree, start_offset + 4, subneg_len - 4,
160         "Value: %s", format_text(&pd[start_offset + 4], subneg_len - 4));
161   }
162   return offset;
163 }
164
165 static int
166 telnet_will_wont_do_dont(proto_tree *telnet_tree, const u_char *pd,
167                         int start_offset, char *type)
168 {
169   int offset = start_offset;
170   const char *opt;
171
172   offset += 2;  /* skip IAC and WILL,WONT,DO,DONT} */
173   if (pd[offset] > NOPTIONS)
174     opt = "<unknown option>";
175   else
176     opt = options[pd[offset]];
177   offset++;
178                       
179   proto_tree_add_text(telnet_tree, start_offset, 3,
180                         "Command: %s %s", type, opt);
181   return offset;
182 }
183
184 static int
185 telnet_command(proto_tree *telnet_tree, const u_char *pd,
186                 int start_offset, int max_data) 
187 {
188   int offset = start_offset;
189   u_char optcode;
190   
191   offset += 1;  /* skip IAC */
192   optcode = pd[offset];
193   offset++;
194   switch(optcode) {
195
196   case TN_EOF:
197     proto_tree_add_text(telnet_tree, start_offset, 2,
198                         "Command: End of File");
199     break;
200
201   case TN_SUSP:
202     proto_tree_add_text(telnet_tree, start_offset, 2,
203                         "Command: Suspend Current Process");
204     break;
205
206   case TN_ABORT:
207     proto_tree_add_text(telnet_tree, start_offset, 2,
208                         "Command: Abort Process");
209     break;
210
211   case TN_EOR:
212     proto_tree_add_text(telnet_tree, start_offset, 2,
213                         "Command: End of Record");
214     break;
215
216   case TN_SE:
217     proto_tree_add_text(telnet_tree, start_offset, 2,
218                         "Command: Suboption End");
219     break;
220
221   case TN_NOP:
222     proto_tree_add_text(telnet_tree, start_offset, 2,
223                         "Command: No Operation");
224     break;
225
226   case TN_DM:
227     proto_tree_add_text(telnet_tree, start_offset, 2,
228                         "Command: Data Mark");
229     break;
230
231   case TN_BRK:
232     proto_tree_add_text(telnet_tree, start_offset, 2,
233                         "Command: Break");
234     break;
235
236   case TN_IP:
237     proto_tree_add_text(telnet_tree, start_offset, 2,
238                         "Command: Interrupt Process");
239     break;
240
241   case TN_AO:
242     proto_tree_add_text(telnet_tree, start_offset, 2,
243                         "Command: Abort Output");
244     break;
245
246   case TN_AYT:
247     proto_tree_add_text(telnet_tree, start_offset, 2,
248                         "Command: Are You There?");
249     break;
250
251   case TN_EC:
252     proto_tree_add_text(telnet_tree, start_offset, 2,
253                         "Command: Escape Character");
254     break;
255
256   case TN_EL:
257     proto_tree_add_text(telnet_tree, start_offset, 2,
258                         "Command: Erase Line");
259     break;
260
261   case TN_GA:
262     proto_tree_add_text(telnet_tree, start_offset, 2,
263                         "Command: Go Ahead");
264     break;
265
266   case TN_SB:
267     offset = telnet_sub_option(telnet_tree, pd, start_offset);
268     break;
269
270   case TN_WILL:
271     offset = telnet_will_wont_do_dont(telnet_tree, pd, start_offset,
272                                         "Will");
273     break;
274
275   case TN_WONT:
276     offset = telnet_will_wont_do_dont(telnet_tree, pd, start_offset,
277                                         "Won't");
278     break;
279
280   case TN_DO:
281     offset = telnet_will_wont_do_dont(telnet_tree, pd, start_offset,
282                                         "Do");
283     break;
284
285   case TN_DONT:
286     offset = telnet_will_wont_do_dont(telnet_tree, pd, start_offset,
287                                         "Don't");
288     break;
289   }
290
291   return offset;
292 }
293
294 void
295 dissect_telnet(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
296 {
297         proto_tree      *telnet_tree, *ti;
298         int max_data = pi.captured_len - offset;
299
300         if (check_col(fd, COL_PROTOCOL))
301                 col_add_str(fd, COL_PROTOCOL, "TELNET");
302
303         if (check_col(fd, COL_INFO)) {
304
305           col_add_fstr(fd, COL_INFO, "Telnet Data ...");
306
307         }
308
309         if (tree) {
310           int data_offset;
311           int data_len;
312
313           ti = proto_tree_add_item(tree, proto_telnet, offset, END_OF_FRAME, NULL);
314           telnet_tree = proto_item_add_subtree(ti, ett_telnet);
315
316           data_offset = offset;
317           data_len = 0;
318
319           /*
320            * Scan through the buffer looking for an IAC byte.
321            */
322           while (offset < pi.captured_len) {
323             if (pd[offset] == TN_IAC) {
324               /*
325                * We found an IAC byte.
326                * If there's any data before it, add that data to the
327                * tree.
328                */
329               if (data_len > 0) {
330                 proto_tree_add_text(telnet_tree, data_offset, data_len,
331                         "Data: %s", format_text(&pd[data_offset], data_len));
332                 data_len = 0;
333                 data_offset = offset;
334               }
335               
336               /*
337                * Now interpret the command.
338                */
339               offset = telnet_command(telnet_tree, pd, offset, max_data);
340               data_offset = offset;
341             }
342             else {
343               data_len++;
344               offset++;
345             }
346           }
347
348           /*
349            * We've reached the end of the buffer.
350            * If there's any data left, add it to the tree.
351            */
352           if (data_len > 0) {
353             proto_tree_add_text(telnet_tree, data_offset, data_len, "Data: %s",
354                         format_text(&pd[data_offset], data_len));
355           }
356         }
357 }
358
359 void
360 proto_register_telnet(void)
361 {
362 /*        static hf_register_info hf[] = {
363                 { &variable,
364                 { "Name",           "telnet.abbreviation", TYPE, VALS_POINTER }},
365         };*/
366         static gint *ett[] = {
367                 &ett_telnet,
368                 &ett_telnet_subopt,
369         };
370
371         proto_telnet = proto_register_protocol("Telnet", "telnet");
372  /*       proto_register_field_array(proto_telnet, hf, array_length(hf));*/
373         proto_register_subtree_array(ett, array_length(ett));
374 }