Squelch a complaint from Visual C++ 6.0 (the code was OK beforehand, at
[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.8 2000/01/07 22:05:41 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 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 void telnet_sub_option(proto_tree *telnet_tree, char *rr, int *i, int offset, int max_data)
119 {
120   proto_tree *ti, *option_tree;
121   int subneg_len, req, si1, not_found = 1;
122   volatile int i1;
123   char *opt, sub_opt_data[1500];
124
125   memset(sub_opt_data, '\0', sizeof(sub_opt_data));
126
127   /* Figure out the option and type */
128
129   opt = options[(unsigned int)rr[*i]];
130   req = (unsigned int)rr[*i + 1];
131
132   i1 = *i + 2; si1 = i1;
133   while ((i1 < max_data) && (not_found)) {  
134
135     if ((unsigned char)rr[i1] == (unsigned char)TN_IAC)
136       not_found = 0;
137     else
138       i1++;
139
140   }
141
142   subneg_len = i1 - *i + 2;
143
144   ti = proto_tree_add_text(telnet_tree, offset, subneg_len, "Suboption Begin: %s", opt);
145
146   option_tree = proto_item_add_subtree(ti, ett_telnet_subopt);
147
148   proto_tree_add_text(option_tree, offset + 2, subneg_len - 2, "%s %s", (req ? "Send your" : "Here's my"), opt);
149
150   if (req == 0) {  /* Add the value */
151
152     memcpy(sub_opt_data, rr + *i + 2, subneg_len - 2);
153     proto_tree_add_text(option_tree, offset + 4, subneg_len - 4, "Value: %s", format_text(sub_opt_data, subneg_len - 4));
154     *i += subneg_len - 2;
155
156   }
157   else {
158
159     *i += subneg_len - 2;
160
161   }
162 }
163
164 void telnet_command(proto_tree *telnet_tree, char *rr, int *i, int offset, int max_data) 
165 {
166   char *opt;
167   
168   switch((unsigned char)rr[*i]) {
169
170   case TN_EOF:
171
172     proto_tree_add_text(telnet_tree, offset, 2, "Command: End of File");
173     (*i)++;
174     break;
175
176   case TN_SUSP:
177
178     proto_tree_add_text(telnet_tree, offset, 2, "Command: Suspend Current Process");
179     (*i)++;
180     break;
181
182   case TN_ABORT:
183
184     proto_tree_add_text(telnet_tree, offset, 2, "Command: Abort Process");
185     (*i)++;
186     break;
187
188   case TN_EOR:
189
190     proto_tree_add_text(telnet_tree, offset, 2, "Command: End of Record");
191     (*i)++;
192     break;
193
194   case TN_SE:
195
196     proto_tree_add_text(telnet_tree, offset, 2, "Command: Suboption End");
197     (*i)++;
198     break;
199
200   case TN_NOP:
201
202     proto_tree_add_text(telnet_tree, offset, 2, "Command: No Operation");
203     (*i)++;
204     break;
205
206   case TN_DM:
207
208     proto_tree_add_text(telnet_tree, offset, 2, "Command: Data Mark");
209     (*i)++;
210     break;
211
212   case TN_BRK:
213
214     proto_tree_add_text(telnet_tree, offset, 2, "Command: Break");
215     (*i)++;
216     break;
217
218   case TN_IP:
219
220     proto_tree_add_text(telnet_tree, offset, 2, "Command: Interrupt Process");
221     (*i)++;
222     break;
223
224   case TN_AO:
225
226     proto_tree_add_text(telnet_tree, offset, 2, "Command: Abort Output");
227     (*i)++;
228     break;
229
230   case TN_AYT:
231
232     proto_tree_add_text(telnet_tree, offset, 2, "Command: Are You There?");
233     (*i)++;
234     break;
235
236   case TN_EC:
237
238     proto_tree_add_text(telnet_tree, offset, 2, "Command: Escape Character");
239     (*i)++;
240     break;
241
242   case TN_EL:
243
244     proto_tree_add_text(telnet_tree, offset, 2, "Command: Erase Line");
245     (*i)++;
246     break;
247
248   case TN_GA:
249
250     proto_tree_add_text(telnet_tree, offset, 2, "Command: Go Ahead");
251     (*i)++;
252     break;
253
254   case TN_SB:
255
256     (*i)++;
257     telnet_sub_option(telnet_tree, rr, i, offset, max_data);
258     break;
259
260   case TN_WILL:
261
262     if (rr[*i + 1] > (sizeof(options)/sizeof(char *)))
263       opt = "<unknown option>";
264     else
265       opt = options[(unsigned int)rr[*i + 1]];
266                       
267     proto_tree_add_text(telnet_tree, offset, 3, "Command: Will %s", opt);
268     *i += 2; /* skip two chars */
269     break;
270
271   case TN_WONT:
272
273     if (rr[*i + 1] > (sizeof(options)/sizeof(char *)))
274       opt = "<unknown option>";
275     else
276       opt = options[(unsigned int)rr[*i + 1]];
277                       
278     proto_tree_add_text(telnet_tree, offset, 3, "Command: Won't %s", opt);
279     *i += 2; /* skip two chars */
280     break;
281
282   case TN_DO:
283
284     if (rr[*i + 1] > (sizeof(options)/sizeof(char *)))
285       opt = "<unknown option>";
286     else
287       opt = options[(unsigned int)rr[*i + 1]];
288                       
289     proto_tree_add_text(telnet_tree, offset, 3, "Command: Do %s", opt);
290     *i += 2; /* skip two chars */
291     break;
292
293   case TN_DONT:
294
295     if (rr[*i + 1] > (sizeof(options)/sizeof(char *)))
296       opt = "<unknown option>";
297     else
298       opt = options[(unsigned int)rr[*i + 1]];
299                       
300     proto_tree_add_text(telnet_tree, offset, 3, "Command: Don't %s", opt);
301     *i += 2; /* skip two chars */
302     break;
303
304   }
305
306 }
307
308 void
309 dissect_telnet(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
310 {
311         proto_tree      *telnet_tree, *ti;
312         gchar           rr[1500];
313         int i1;
314         int i2;
315         int max_data = pi.captured_len - offset;
316
317         memset(rr, '\0', sizeof(rr));
318
319         if (check_col(fd, COL_PROTOCOL))
320                 col_add_str(fd, COL_PROTOCOL, "TELNET");
321
322         if (check_col(fd, COL_INFO)) {
323
324           col_add_fstr(fd, COL_INFO, "Telnet Data ...");
325
326         }
327
328         if (tree) {
329
330           char data[1500];
331           int i3;
332
333           memset(data, '\0', sizeof(data));
334
335           memcpy(rr, pd + offset, max_data);
336
337           ti = proto_tree_add_item(tree, proto_telnet, offset, END_OF_FRAME, NULL);
338           telnet_tree = proto_item_add_subtree(ti, ett_telnet);
339
340           i1 = i2 = i3 = 0;
341
342           while (i1 < max_data) {
343
344             if ((unsigned char)rr[i1] == (unsigned char)TN_IAC) {
345
346               if (strlen(data) > 0) {
347
348                 proto_tree_add_text(telnet_tree, offset + i2, strlen(data), "Data: %s", format_text(data, strlen(data)));
349                 memset(data, '\0', sizeof(data));
350                 i3 = 0;
351
352               }
353               
354               i1++;
355               telnet_command(telnet_tree, rr, &i1, offset + i1 - 1, max_data);
356               i2 = i1;
357
358             }
359             else {
360
361               data[i3] = rr[i1];
362               i3++;
363               i1++;
364
365
366             }
367           }
368
369           if (strlen(data) > 0) { /* Still some data to add */
370
371             proto_tree_add_text(telnet_tree, offset + i2, strlen(data), "Data: %s", format_text(data, strlen(data)));
372
373           }
374
375         }
376
377 }
378
379 void
380 proto_register_telnet(void)
381 {
382 /*        static hf_register_info hf[] = {
383                 { &variable,
384                 { "Name",           "telnet.abbreviation", TYPE, VALS_POINTER }},
385         };*/
386         static gint *ett[] = {
387                 &ett_telnet,
388                 &ett_telnet_subopt,
389         };
390
391         proto_telnet = proto_register_protocol("Telnet", "telnet");
392  /*       proto_register_field_array(proto_telnet, hf, array_length(hf));*/
393         proto_register_subtree_array(ett, array_length(ett));
394 }