Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-exec.c
bloba901fda3a8d1d4195928dafdc78add78b93a5491
1 /* packet-exec.c
2 * Routines for exec (rexec) dissection
3 * Copyright 2006, Stephen Fisher (see AUTHORS file)
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * Based on BSD rexecd code/man page and parts of packet-rlogin.c
11 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include "config.h"
16 #include <epan/packet.h>
17 #include <epan/conversation.h>
18 #include <epan/prefs.h>
19 #include <wsutil/str_util.h>
21 /* The exec protocol uses TCP port 512 per its IANA assignment */
22 #define EXEC_PORT 512
24 /* Variables for our preferences */
25 static bool preference_info_show_username = true;
26 static bool preference_info_show_command;
28 void proto_register_exec(void);
29 void proto_reg_handoff_exec(void);
31 /* Initialize the protocol and registered fields */
32 static int proto_exec;
34 static int hf_exec_stderr_port;
35 static int hf_exec_username;
36 static int hf_exec_password;
37 static int hf_exec_command;
38 static int hf_exec_client_server_data;
39 static int hf_exec_server_client_data;
41 /* Initialize the subtree pointers */
42 static int ett_exec;
44 #define EXEC_STDERR_PORT_LEN 5
45 #define EXEC_USERNAME_LEN 16
46 #define EXEC_PASSWORD_LEN 16
47 #define EXEC_COMMAND_LEN 256 /* Longer depending on server operating system? */
49 /* Initialize the structure that will be tied to each conversation.
50 * This is used to display the username and/or command in the INFO column of
51 * each packet of the conversation. */
53 typedef enum {
54 NONE,
55 WAIT_FOR_STDERR_PORT,
56 WAIT_FOR_USERNAME,
57 WAIT_FOR_PASSWORD,
58 WAIT_FOR_COMMAND,
59 WAIT_FOR_DATA
60 } exec_session_state_t;
63 typedef struct {
64 /* Packet number within the conversation */
65 unsigned first_packet_number, second_packet_number;
66 unsigned third_packet_number, fourth_packet_number;
68 /* The following variables are given values from session_state_t
69 * above to keep track of where we are in the beginning of the session
70 * (when the username and other fields show up). This is necessary for
71 * when the user clicks randomly through the initial packets instead of
72 * going in order.
75 /* Track where we are in the conversation */
76 exec_session_state_t state;
77 exec_session_state_t first_packet_state, second_packet_state;
78 exec_session_state_t third_packet_state, fourth_packet_state;
80 char *username;
81 char *command;
82 } exec_hash_entry_t;
85 static int
86 dissect_exec(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
88 /* Set up structures needed to add the protocol subtree and manage it */
89 proto_item *ti;
90 proto_tree *exec_tree=NULL;
92 /* Variables for extracting and displaying data from the packet */
93 unsigned char *field_stringz; /* Temporary storage for each field we extract */
95 int length;
96 unsigned offset = 0;
97 conversation_t *conversation;
98 exec_hash_entry_t *hash_info;
100 conversation = find_or_create_conversation(pinfo);
102 /* Retrieve information from conversation
103 * or add it if it isn't there yet
105 hash_info = (exec_hash_entry_t *)conversation_get_proto_data(conversation, proto_exec);
106 if(!hash_info){
107 hash_info = wmem_new(wmem_file_scope(), exec_hash_entry_t);
109 hash_info->first_packet_number = pinfo->num;
110 hash_info->second_packet_number = 0;
111 hash_info->third_packet_number = 0;
112 hash_info->fourth_packet_number = 0;
114 hash_info->state = WAIT_FOR_STDERR_PORT; /* The first field we'll see */
116 /* Start with empty username and command strings */
117 hash_info->username=NULL;
118 hash_info->command=NULL;
120 /* These will be set on the first pass by the first
121 * four packets of the conversation
123 hash_info->first_packet_state = NONE;
124 hash_info->second_packet_state = NONE;
125 hash_info->third_packet_state = NONE;
126 hash_info->fourth_packet_state = NONE;
128 conversation_add_proto_data(conversation, proto_exec, hash_info);
131 /* Store the number of the first three packets of this conversation
132 * as we reach them the first time */
134 if(!hash_info->second_packet_number
135 && pinfo->num > hash_info->first_packet_number){
136 /* We're on the second packet of the conversation */
137 hash_info->second_packet_number = pinfo->num;
138 } else if(hash_info->second_packet_number
139 && !hash_info->third_packet_number
140 && pinfo->num > hash_info->second_packet_number) {
141 /* We're on the third packet of the conversation */
142 hash_info->third_packet_number = pinfo->num;
143 } else if(hash_info->third_packet_number
144 && !hash_info->fourth_packet_number
145 && pinfo->num > hash_info->third_packet_number) {
146 /* We're on the fourth packet of the conversation */
147 hash_info->fourth_packet_number = pinfo->num;
150 /* Save this packet's state so we can retrieve it if this packet
151 * is selected again later. If the packet's state was already stored,
152 * then retrieve it */
153 if(pinfo->num == hash_info->first_packet_number){
154 if(hash_info->first_packet_state == NONE){
155 hash_info->first_packet_state = hash_info->state;
156 } else {
157 hash_info->state = hash_info->first_packet_state;
161 if(pinfo->num == hash_info->second_packet_number){
162 if(hash_info->second_packet_state == NONE){
163 hash_info->second_packet_state = hash_info->state;
164 } else {
165 hash_info->state = hash_info->second_packet_state;
169 if(pinfo->num == hash_info->third_packet_number){
170 if(hash_info->third_packet_state == NONE){
171 hash_info->third_packet_state = hash_info->state;
172 } else {
173 hash_info->state = hash_info->third_packet_state;
177 if(pinfo->num == hash_info->fourth_packet_number){
178 if(hash_info->fourth_packet_state == NONE){
179 hash_info->fourth_packet_state = hash_info->state;
180 } else {
181 hash_info->state = hash_info->fourth_packet_state;
185 col_set_str(pinfo->cinfo, COL_PROTOCOL, "EXEC");
187 /* First, clear the info column */
188 col_clear(pinfo->cinfo, COL_INFO);
190 /*username */
191 if(hash_info->username && preference_info_show_username == true){
192 col_append_fstr(pinfo->cinfo, COL_INFO, "Username:%s ", hash_info->username);
195 /* Command */
196 if(hash_info->command && preference_info_show_command == true){
197 col_append_fstr(pinfo->cinfo, COL_INFO, "Command:%s ", hash_info->command);
200 /* create display subtree for the protocol */
201 ti = proto_tree_add_item(tree, proto_exec, tvb, 0, -1, ENC_NA);
202 exec_tree = proto_item_add_subtree(ti, ett_exec);
204 /* If this packet doesn't end with a null terminated string,
205 * then it must be session data only and we can skip looking
206 * for the other fields.
208 if(tvb_find_uint8(tvb, tvb_captured_length(tvb)-1, 1, '\0') == -1){
209 hash_info->state = WAIT_FOR_DATA;
212 if(hash_info->state == WAIT_FOR_STDERR_PORT
213 && tvb_reported_length_remaining(tvb, offset)){
214 field_stringz = tvb_get_stringz_enc(pinfo->pool, tvb, offset, &length, ENC_ASCII);
216 /* Check if this looks like the stderr_port field.
217 * It is optional, so it may only be 1 character long
218 * (the NULL)
220 if(length == 1 || (isdigit_string(field_stringz)
221 && length <= EXEC_STDERR_PORT_LEN)){
222 proto_tree_add_string(exec_tree, hf_exec_stderr_port, tvb, offset, length, (char*)field_stringz);
223 /* Next field we need */
224 hash_info->state = WAIT_FOR_USERNAME;
225 } else {
226 /* Since the data doesn't match this field, it must be data only */
227 hash_info->state = WAIT_FOR_DATA;
230 /* Used if the next field is in the same packet */
231 offset += length;
235 if(hash_info->state == WAIT_FOR_USERNAME
236 && tvb_reported_length_remaining(tvb, offset)){
237 field_stringz = tvb_get_stringz_enc(pinfo->pool, tvb, offset, &length, ENC_ASCII);
239 /* Check if this looks like the username field */
240 if(length != 1 && length <= EXEC_USERNAME_LEN
241 && isprint_string(field_stringz)){
242 proto_tree_add_string(exec_tree, hf_exec_username, tvb, offset, length, (char*)field_stringz);
244 /* Store the username so we can display it in the
245 * info column of the entire conversation
247 if(!hash_info->username){
248 hash_info->username=wmem_strdup(wmem_file_scope(), (char*)field_stringz);
251 /* Next field we need */
252 hash_info->state = WAIT_FOR_PASSWORD;
253 } else {
254 /* Since the data doesn't match this field, it must be data only */
255 hash_info->state = WAIT_FOR_DATA;
258 /* Used if the next field is in the same packet */
259 offset += length;
263 if(hash_info->state == WAIT_FOR_PASSWORD
264 && tvb_reported_length_remaining(tvb, offset)){
265 field_stringz = tvb_get_stringz_enc(pinfo->pool, tvb, offset, &length, ENC_ASCII);
267 /* Check if this looks like the password field */
268 if(length != 1 && length <= EXEC_PASSWORD_LEN
269 && isprint_string(field_stringz)){
270 proto_tree_add_string(exec_tree, hf_exec_password, tvb, offset, length, (char*)field_stringz);
273 /* Used if the next field is in the same packet */
274 offset += length;
275 /* Next field we are looking for */
276 hash_info->state = WAIT_FOR_COMMAND;
280 if(hash_info->state == WAIT_FOR_COMMAND
281 && tvb_reported_length_remaining(tvb, offset)){
282 field_stringz = tvb_get_stringz_enc(pinfo->pool, tvb, offset, &length, ENC_ASCII);
284 /* Check if this looks like the command field */
285 if(length != 1 && length <= EXEC_COMMAND_LEN
286 && isprint_string(field_stringz)){
287 proto_tree_add_string(exec_tree, hf_exec_command, tvb, offset, length, (char*)field_stringz);
289 /* Store the command so we can display it in the
290 * info column of the entire conversation
292 if(!hash_info->command){
293 hash_info->command=wmem_strdup(wmem_file_scope(), (char*)field_stringz);
296 } else {
297 /* Since the data doesn't match this field, it must be data only */
298 hash_info->state = WAIT_FOR_DATA;
303 if(hash_info->state == WAIT_FOR_DATA
304 && tvb_reported_length_remaining(tvb, offset)){
305 if(pinfo->destport == EXEC_PORT){
306 /* Packet going to the server */
307 /* offset = 0 since the whole packet is data */
308 proto_tree_add_item(exec_tree, hf_exec_client_server_data, tvb, 0, -1, ENC_NA);
310 col_append_str(pinfo->cinfo, COL_INFO, "Client -> Server data");
311 } else {
312 /* This packet must be going back to the client */
313 /* offset = 0 since the whole packet is data */
314 proto_tree_add_item(exec_tree, hf_exec_server_client_data, tvb, 0, -1, ENC_NA);
316 col_append_str(pinfo->cinfo, COL_INFO, "Server -> Client Data");
320 /* We haven't seen all of the fields yet */
321 if(hash_info->state < WAIT_FOR_DATA){
322 col_set_str(pinfo->cinfo, COL_INFO, "Session Establishment");
324 return tvb_captured_length(tvb);
327 void
328 proto_register_exec(void)
330 static hf_register_info hf[] =
332 { &hf_exec_stderr_port, { "Stderr port (optional)", "exec.stderr_port",
333 FT_STRINGZ, BASE_NONE, NULL, 0,
334 "Client port that is listening for stderr stream from server", HFILL } },
336 { &hf_exec_username, { "Client username", "exec.username",
337 FT_STRINGZ, BASE_NONE, NULL, 0,
338 "Username client uses to log in to the server.", HFILL } },
340 { &hf_exec_password, { "Client password", "exec.password",
341 FT_STRINGZ, BASE_NONE, NULL, 0,
342 "Password client uses to log in to the server.", HFILL } },
344 { &hf_exec_command, { "Command to execute", "exec.command",
345 FT_STRINGZ, BASE_NONE, NULL, 0,
346 "Command client is requesting the server to run.", HFILL } },
348 { &hf_exec_client_server_data, { "Client -> Server Data", "exec.client_server_data",
349 FT_BYTES, BASE_NONE, NULL, 0,
350 NULL, HFILL } },
352 { &hf_exec_server_client_data, { "Server -> Client Data", "exec.server_client_data",
353 FT_BYTES, BASE_NONE, NULL, 0,
354 NULL, HFILL } },
358 static int *ett[] =
360 &ett_exec
363 module_t *exec_module;
365 /* Register the protocol name and description */
366 proto_exec = proto_register_protocol("Remote Process Execution", "EXEC", "exec");
368 /* Register the dissector function */
369 register_dissector("exec", dissect_exec, proto_exec);
371 /* Required function calls to register the header fields and subtrees used */
372 proto_register_field_array(proto_exec, hf, array_length(hf));
373 proto_register_subtree_array(ett, array_length(ett));
375 /* Register preferences module */
376 exec_module = prefs_register_protocol(proto_exec, NULL);
378 /* Register our preferences */
379 prefs_register_bool_preference(exec_module, "info_show_username",
380 "Show username in info column",
381 "Controls the display of the session's username in the info column. This is only displayed if the packet containing it was seen during this capture session.", &preference_info_show_username);
383 prefs_register_bool_preference(exec_module, "info_show_command",
384 "Show command in info column",
385 "Controls the display of the command being run on the server by this session in the info column. This is only displayed if the packet containing it was seen during this capture session.", &preference_info_show_command);
389 /* Entry function */
390 void
391 proto_reg_handoff_exec(void)
393 dissector_add_uint_with_preference("tcp.port", EXEC_PORT, find_dissector("exec"));
397 * Editor modelines - https://www.wireshark.org/tools/modelines.html
399 * Local variables:
400 * c-basic-offset: 8
401 * tab-width: 8
402 * indent-tabs-mode: t
403 * End:
405 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
406 * :indentSize=8:tabSize=8:noTabs=false: