コード例 #1
0
static void
dissect_rsh(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	/* Set up structures needed to add the protocol subtree and manage it */
	proto_item *ti;
	proto_tree *rsh_tree=NULL;

	/* Variables for extracting and displaying data from the packet */
	guchar *field_stringz; /* Temporary storage for each field we extract */

	gint length;
	guint offset = 0;
	conversation_t *conversation;
	rsh_hash_entry_t *hash_info;

	conversation = find_or_create_conversation(pinfo);

	/* Retrieve information from conversation
	 * or add it if it isn't there yet
	 */
	hash_info = conversation_get_proto_data(conversation, proto_rsh);
	if(!hash_info){
		hash_info = se_alloc(sizeof(rsh_hash_entry_t));

		hash_info->first_packet_number = pinfo->fd->num;
		hash_info->second_packet_number = 0;
		hash_info->third_packet_number  = 0;
		hash_info->fourth_packet_number  = 0;

		hash_info->state = WAIT_FOR_STDERR_PORT; /* The first field we'll see */

		/* Start with empty username and command strings */
		hash_info->client_username=NULL;
		hash_info->server_username=NULL;
		hash_info->command=NULL;

		/* These will be set on the first pass by the first
		 * four packets of the conversation
		 */
		hash_info->first_packet_state  = NONE;
		hash_info->second_packet_state = NONE;
		hash_info->third_packet_state  = NONE;
		hash_info->fourth_packet_state  = NONE;

		conversation_add_proto_data(conversation, proto_rsh, hash_info);
	}

	/* Store the number of the first three packets of this conversation
	 * as we reach them the first time */

	if(!hash_info->second_packet_number
	&& pinfo->fd->num > hash_info->first_packet_number){
		/* We're on the second packet of the conversation */
		hash_info->second_packet_number = pinfo->fd->num;
	} else if(hash_info->second_packet_number
	 && !hash_info->third_packet_number
	 && pinfo->fd->num > hash_info->second_packet_number) {
		/* We're on the third packet of the conversation */
		hash_info->third_packet_number = pinfo->fd->num;
	} else if(hash_info->third_packet_number
	 && !hash_info->fourth_packet_number
	 && pinfo->fd->num > hash_info->third_packet_number) {
		/* We're on the fourth packet of the conversation */
		hash_info->fourth_packet_number = pinfo->fd->num;
	}

	/* Save this packet's state so we can retrieve it if this packet
	 * is selected again later.  If the packet's state was already stored,
	 * then retrieve it */
	if(pinfo->fd->num == hash_info->first_packet_number){
		if(hash_info->first_packet_state == NONE){
			hash_info->first_packet_state = hash_info->state;
		} else {
			hash_info->state = hash_info->first_packet_state;
		}
	}

	if(pinfo->fd->num == hash_info->second_packet_number){
		if(hash_info->second_packet_state == NONE){
			hash_info->second_packet_state = hash_info->state;
		} else {
			hash_info->state = hash_info->second_packet_state;
		}
	}

	if(pinfo->fd->num == hash_info->third_packet_number){
		if(hash_info->third_packet_state == NONE){
			hash_info->third_packet_state = hash_info->state;
		} else {
			hash_info->state = hash_info->third_packet_state;
		}
	}

	if(pinfo->fd->num == hash_info->fourth_packet_number){
		if(hash_info->fourth_packet_state == NONE){
			hash_info->fourth_packet_state = hash_info->state;
		} else {
			hash_info->state = hash_info->fourth_packet_state;
		}
	}

	col_set_str(pinfo->cinfo, COL_PROTOCOL, "RSH");

	if(check_col(pinfo->cinfo, COL_INFO)){
		/* First, clear the info column */
		col_clear(pinfo->cinfo, COL_INFO);

		/* Client username */
		if(hash_info->client_username && preference_info_show_client_username == TRUE){
			col_append_fstr(pinfo->cinfo, COL_INFO, "Client username:%s ", hash_info->client_username);
		}

		/* Server username */
		if(hash_info->server_username && preference_info_show_server_username == TRUE){
			col_append_fstr(pinfo->cinfo, COL_INFO, "Server username:%s ", hash_info->server_username);
		}

		/* Command */
		if(hash_info->command && preference_info_show_command == TRUE){
			col_append_fstr(pinfo->cinfo, COL_INFO, "Command:%s ", hash_info->command);
		}
	}

	/* create display subtree for the protocol */
	ti = proto_tree_add_item(tree, proto_rsh, tvb, 0, -1, ENC_NA);
	rsh_tree = proto_item_add_subtree(ti, ett_rsh);

	/* If this packet doesn't end with a null terminated string,
	 * then it must be session data only and we can skip looking
	 * for the other fields.
	 */
	if(tvb_find_guint8(tvb, tvb_length(tvb)-1, 1, '\0') == -1){
		hash_info->state = WAIT_FOR_DATA;
	}

	if(hash_info->state == WAIT_FOR_STDERR_PORT
	&& tvb_length_remaining(tvb, offset)){
		field_stringz = tvb_get_ephemeral_stringz(tvb, offset, &length);

		/* Check if this looks like the stderr_port field.
		 * It is optional, so it may only be 1 character long
		 * (the NULL)
		 */
		if(length == 1 || (isdigit_string(field_stringz)
		&& length <= RSH_STDERR_PORT_LEN)){
			proto_tree_add_string(rsh_tree, hf_rsh_stderr_port, tvb, offset, length, (gchar*)field_stringz);
			 /* Next field we need */
			hash_info->state = WAIT_FOR_CLIENT_USERNAME;
		} else {
			/* Since the data doesn't match this field, it must be data only */
			hash_info->state = WAIT_FOR_DATA;
		}

		/* Used if the next field is in the same packet */
		offset += length;
	}


	if(hash_info->state == WAIT_FOR_CLIENT_USERNAME
	&& tvb_length_remaining(tvb, offset)){
		field_stringz = tvb_get_ephemeral_stringz(tvb, offset, &length);

		/* Check if this looks like the username field */
		if(length != 1 && length <= RSH_CLIENT_USERNAME_LEN
		&& isprint_string(field_stringz)){
			proto_tree_add_string(rsh_tree, hf_rsh_client_username, tvb, offset, length, (gchar*)field_stringz);

			/* Store the client username so we can display it in the
			 * info column of the entire conversation
			 */
			if(!hash_info->client_username){
				hash_info->client_username=se_strdup((gchar*)field_stringz);
			}

			 /* Next field we need */
			hash_info->state = WAIT_FOR_SERVER_USERNAME;
		} else {
			/* Since the data doesn't match this field, it must be data only */
			hash_info->state = WAIT_FOR_DATA;
		}

		/* Used if the next field is in the same packet */
		offset += length;
	}


	if(hash_info->state == WAIT_FOR_SERVER_USERNAME
	&& tvb_length_remaining(tvb, offset)){
		field_stringz = tvb_get_ephemeral_stringz(tvb, offset, &length);

		/* Check if this looks like the password field */
		if(length != 1 && length <= RSH_SERVER_USERNAME_LEN
		&& isprint_string(field_stringz)){
			proto_tree_add_string(rsh_tree, hf_rsh_server_username, tvb, offset, length, (gchar*)field_stringz);

			/* Store the server username so we can display it in the
			 * info column of the entire conversation
			 */
			if(!hash_info->server_username){
				hash_info->server_username=se_strdup((gchar*)field_stringz);
			}

			/* Next field we need */
			hash_info->state = WAIT_FOR_COMMAND;
		} else {
			/* Since the data doesn't match this field, it must be data only */
			hash_info->state = WAIT_FOR_DATA;
		}

		/* Used if the next field is in the same packet */
		offset += length;
		 /* Next field we are looking for */
		hash_info->state = WAIT_FOR_COMMAND;
	}


	if(hash_info->state == WAIT_FOR_COMMAND
	&& tvb_length_remaining(tvb, offset)){
		field_stringz = tvb_get_ephemeral_stringz(tvb, offset, &length);

		/* Check if this looks like the command field */
		if(length != 1 && length <= RSH_COMMAND_LEN
		&& isprint_string(field_stringz)){
			proto_tree_add_string(rsh_tree, hf_rsh_command, tvb, offset, length, (gchar*)field_stringz);

			/* Store the command so we can display it in the
			 * info column of the entire conversation
			 */
			if(!hash_info->command){
				hash_info->command=se_strdup((gchar*)field_stringz);
			}

		} else {
			/* Since the data doesn't match this field, it must be data only */
			hash_info->state = WAIT_FOR_DATA;
		}
	}


	if(hash_info->state == WAIT_FOR_DATA
	&& tvb_length_remaining(tvb, offset)){
		if(pinfo->destport == RSH_PORT){
			/* Packet going to the server */
			/* offset = 0 since the whole packet is data */
			proto_tree_add_text(rsh_tree, tvb, 0, -1, "Client -> Server Data");

			col_append_str(pinfo->cinfo, COL_INFO, "Client -> Server data");
		} else {
			/* This packet must be going back to the client */
			/* offset = 0 since the whole packet is data */
			proto_tree_add_text(rsh_tree, tvb, 0, -1, "Server -> Client Data");

			col_append_str(pinfo->cinfo, COL_INFO, "Server -> Client Data");
		}
	}

	/* We haven't seen all of the fields yet */
	if(hash_info->state < WAIT_FOR_DATA){
		col_set_str(pinfo->cinfo, COL_INFO, "Session Establishment");
	}
}
コード例 #2
0
ファイル: packet-multipart.c プロジェクト: aminema/wireshark
/*
 * Process a multipart body-part:
 *      MIME-part-headers [ line-end *OCTET ]
 *      line-end dashed-boundary transport-padding line-end
 *
 * If applicable, call a media subdissector.
 *
 * Return the offset to the start of the next body-part.
 */
static gint
process_body_part(proto_tree *tree, tvbuff_t *tvb, multipart_info_t *m_info,
                  packet_info *pinfo, gint start, gint idx,
                  gboolean *last_boundary)
{
    proto_tree *subtree;
    proto_item *ti;
    gint offset = start, next_offset = 0;
    char *parameters = NULL;
    gint body_start, boundary_start, boundary_line_len;

    gchar *content_type_str = NULL;
    gchar *content_encoding_str = NULL;
    char *filename = NULL;
    char *mimetypename = NULL;
    int  len = 0;
    gboolean last_field = FALSE;
    gboolean is_raw_data = FALSE;

    const guint8 *boundary = (guint8 *)m_info->boundary;
    gint boundary_len = m_info->boundary_length;

    ti = proto_tree_add_item(tree, hf_multipart_part, tvb, start, 0, ENC_ASCII|ENC_NA);
    subtree = proto_item_add_subtree(ti, ett_multipart_body);

    /* find the next boundary to find the end of this body part */
    boundary_start = find_next_boundary(tvb, offset, boundary, boundary_len,
                                        &boundary_line_len, last_boundary);

    if (boundary_start <= 0) {
        return -1;
    }

    /*
     * Process the MIME-part-headers
     */

    while (!last_field)
    {
        gint colon_offset;
        char *hdr_str;
        char *header_str;

        /* Look for the end of the header (denoted by cr)
         * 3:d argument to imf_find_field_end() maxlen; must be last offset in the tvb.
         */
        next_offset = imf_find_field_end(tvb, offset, tvb_reported_length_remaining(tvb, offset)+offset, &last_field);
        /* the following should never happen */
        /* If cr not found, won't have advanced - get out to avoid infinite loop! */
        /*
        if (next_offset == offset) {
            break;
        }
        */
        if (last_field && (next_offset+2) <= boundary_start) {
            /* Add the extra CRLF of the last field */
            next_offset += 2;
        } else if((next_offset-2) == boundary_start) {
            /* if CRLF is the start of next boundary it belongs to the boundary and not the field,
               so it's the last field without CRLF */
            last_field = TRUE;
            next_offset -= 2;
        } else if (next_offset > boundary_start) {
            /* if there is no CRLF between last field and next boundary - trim it! */
            next_offset = boundary_start;
        }

        hdr_str = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, next_offset - offset, ENC_ASCII);

        header_str = unfold_and_compact_mime_header(hdr_str, &colon_offset);
        if (colon_offset <= 0) {
            /* if there is no colon it's no header, so break and add complete line to the body */
            next_offset = offset;
            break;
        } else {
            gint hf_index;

            /* Split header name from header value */
            header_str[colon_offset] = '\0';
            hf_index = is_known_multipart_header(header_str, colon_offset);

            if (hf_index == -1) {
                if(isprint_string(hdr_str)) {
                    proto_tree_add_format_text(subtree, tvb, offset, next_offset - offset);
                } else {
                    /* if the header name is unkown and not printable, break and add complete line to the body */
                    next_offset = offset;
                    break;
                }
            } else {
                char *value_str = header_str + colon_offset + 1;

                proto_tree_add_string_format(subtree,
                                             hf_header_array[hf_index], tvb,
                                             offset, next_offset - offset,
                                             (const char *)value_str, "%s",
                                             tvb_format_text(tvb, offset, next_offset - offset));

                switch (hf_index) {
                case POS_ORIGINALCONTENT:
                {
                    gint semicolon_offset;
                    /* The Content-Type starts at colon_offset + 1 or after the type parameter */
                    char* type_str = find_parameter(value_str, "type=", NULL);
                    if(type_str != NULL) {
                        value_str = type_str;
                    }

                    semicolon_offset = index_of_char(
                                           value_str, ';');

                    if (semicolon_offset > 0) {
                        value_str[semicolon_offset] = '\0';
                        m_info->orig_parameters = wmem_strdup(wmem_packet_scope(),
                                                              value_str + semicolon_offset + 1);
                    }

                    m_info->orig_content_type = wmem_ascii_strdown(wmem_packet_scope(), value_str, -1);
                }
                break;
                case POS_CONTENT_TYPE:
                {
                    /* The Content-Type starts at colon_offset + 1 */
                    gint semicolon_offset = index_of_char(
                                                value_str, ';');

                    if (semicolon_offset > 0) {
                        value_str[semicolon_offset] = '\0';
                        parameters = wmem_strdup(wmem_packet_scope(), value_str + semicolon_offset + 1);
                    } else {
                        parameters = NULL;
                    }

                    content_type_str = wmem_ascii_strdown(wmem_packet_scope(), value_str, -1);

                    /* Show content-type in root 'part' label */
                    proto_item_append_text(ti, " (%s)", content_type_str);

                    /* find the "name" parameter in case we don't find a content disposition "filename" */
                    if((mimetypename = find_parameter(parameters, "name=", &len)) != NULL) {
                        mimetypename = g_strndup(mimetypename, len);
                    }

                    if(strncmp(content_type_str, "application/octet-stream",
                               sizeof("application/octet-stream")-1) == 0) {
                        is_raw_data = TRUE;
                    }

                    /* there are only 2 body parts possible and each part has specific content types */
                    if(m_info->protocol && idx == 0
                            && (is_raw_data || g_ascii_strncasecmp(content_type_str, m_info->protocol,
                                    strlen(m_info->protocol)) != 0))
                    {
                        return -1;
                    }
                }
                break;
                case POS_CONTENT_TRANSFER_ENCODING:
                {
                    /* The Content-Transferring starts at colon_offset + 1 */
                    gint cr_offset = index_of_char(value_str, '\r');

                    if (cr_offset > 0) {
                        value_str[cr_offset] = '\0';
                    }

                    content_encoding_str = wmem_ascii_strdown(wmem_packet_scope(), value_str, -1);
                }
                break;
                case POS_CONTENT_DISPOSITION:
                {
                    /* find the "filename" parameter */
                    if((filename = find_parameter(value_str, "filename=", &len)) != NULL) {
                        filename = g_strndup(filename, len);
                    }
                }
                break;
                default:
                    break;
                }
            }
        }
        offset = next_offset;
    }

    body_start = next_offset;

    /*
     * Process the body
     */

    {
        gint body_len = boundary_start - body_start;
        tvbuff_t *tmp_tvb = tvb_new_subset_length(tvb, body_start, body_len);
        /* if multipart subtype is encrypted the protcol string was set */
        /* see: https://msdn.microsoft.com/en-us/library/cc251581.aspx */
        /* there are only 2 body parts possible and each part has specific content types */
        if(m_info->protocol && idx == 1 && is_raw_data)
        {
            gssapi_encrypt_info_t  encrypt;

            memset(&encrypt, 0, sizeof(encrypt));
            encrypt.decrypt_gssapi_tvb=DECRYPT_GSSAPI_NORMAL;

            dissect_kerberos_encrypted_message(tmp_tvb, pinfo, subtree, &encrypt);

            if(encrypt.gssapi_decrypted_tvb) {
                tmp_tvb = encrypt.gssapi_decrypted_tvb;
                is_raw_data = FALSE;
                content_type_str = m_info->orig_content_type;
                parameters = m_info->orig_parameters;
            } else if(encrypt.gssapi_encrypted_tvb) {
                tmp_tvb = encrypt.gssapi_encrypted_tvb;
                proto_tree_add_expert(tree, pinfo, &ei_multipart_decryption_not_possible, tmp_tvb, 0, -1);
            }
        }

        if (!is_raw_data &&
                content_type_str) {

            /*
             * subdissection
             */
            gboolean dissected;

            /*
             * Try and remove any content transfer encoding so that each sub-dissector
             * doesn't have to do it itself
             *
             */

            if(content_encoding_str && remove_base64_encoding) {

                if(!g_ascii_strncasecmp(content_encoding_str, "base64", 6))
                    tmp_tvb = base64_decode(pinfo, tmp_tvb, filename ? filename : (mimetypename ? mimetypename : content_type_str));

            }

            /*
             * First try the dedicated multipart dissector table
             */
            dissected = dissector_try_string(multipart_media_subdissector_table,
                                             content_type_str, tmp_tvb, pinfo, subtree, parameters);
            if (! dissected) {
                /*
                 * Fall back to the default media dissector table
                 */
                dissected = dissector_try_string(media_type_dissector_table,
                                                 content_type_str, tmp_tvb, pinfo, subtree, parameters);
            }
            if (! dissected) {
                const char *save_match_string = pinfo->match_string;
                pinfo->match_string = content_type_str;
                call_dissector_with_data(media_handle, tmp_tvb, pinfo, subtree, parameters);
                pinfo->match_string = save_match_string;
            }
            parameters = NULL; /* Shares same memory as content_type_str */
        } else {
            call_dissector(data_handle, tmp_tvb, pinfo, subtree);
        }
        proto_item_set_len(ti, boundary_start - start);
        if (*last_boundary == TRUE) {
            proto_tree_add_item(tree, hf_multipart_last_boundary, tvb, boundary_start, boundary_line_len, ENC_NA|ENC_ASCII);
        } else {
            proto_tree_add_item(tree, hf_multipart_boundary, tvb, boundary_start, boundary_line_len, ENC_NA|ENC_ASCII);
        }

        g_free(filename);
        g_free(mimetypename);

        return boundary_start + boundary_line_len;
    }
}