/* ---------------------------------------------- */ static int fix_header_len(tvbuff_t *tvb, int offset) { int base_offset, ctrla_offset; char *value; int size; fix_parameter *tag; base_offset = offset; /* get at least the fix version: 8=FIX.x.x */ if (fix_marker(tvb, offset) != 0) { return fix_next_header(tvb, offset); } /* begin string */ ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01); if (ctrla_offset == -1) { /* it should be there, (minimum size is big enough) * if not maybe it's not really * a FIX packet but it's too late to bail out. */ return fix_next_header(tvb, offset +MARKER_LEN) +MARKER_LEN; } offset = ctrla_offset + 1; /* msg length */ if (!(tag = fix_param(tvb, offset)) || tvb_strneql(tvb, offset, "9=", 2)) { /* not a tag or not the BodyLength tag, give up */ return fix_next_header(tvb, offset); } value = tvb_get_ephemeral_string(tvb, tag->value_offset, tag->value_len); /* Fix version, msg type, length and checksum aren't in body length. * If the packet is big enough find the checksum */ size = atoi(value) +tag->ctrla_offset - base_offset +1; if (tvb_length_remaining(tvb, base_offset) > size +4) { /* 10= should be there */ offset = base_offset +size; if (tvb_strneql(tvb, offset, "10=", 3) != 0) { /* No? bogus packet, try to find the next header */ return fix_next_header(tvb, base_offset +MARKER_LEN) +MARKER_LEN; } ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01); if (ctrla_offset == -1) { /* assume checksum is 7 bytes 10=xxx\01 */ return size+7; } return size +ctrla_offset -offset +1; } else { } /* assume checksum is 7 bytes 10=xxx\01 */ return size +7; }
/* check whether the packet looks like SBUS or not */ static gboolean is_esio_pdu(tvbuff_t *tvb) { /* we need at least 8 bytes to determine whether this is Ether-S-I/O or not*/ /* minimal length is 20 bytes*/ if (tvb_captured_length(tvb) < 20) { return FALSE; } /* First four bytes must be "ESIO"*/ if (tvb_strneql(tvb, 0, "ESIO", 4) != 0) { return FALSE; } /* fifth byte must be 0*/ if (tvb_get_guint8(tvb, 4) > 0x00) { return FALSE; } /* sixth byte indicates telegram type and must be 0, 1 or 2*/ if (tvb_get_guint8(tvb, 5) > 0x02) { return FALSE; } /* seventh byte must be 0*/ if (tvb_get_guint8(tvb, 6) > 0x00) { return FALSE; } /* eight byte indicates telegram version and must be 0 (up to now)*/ if (tvb_get_guint8(tvb, 7) > 0x00) { return FALSE; } /*header seems to be Ether-S-I/O*/ return TRUE; }
/* * Unless the first boundary, subsequent boundaries include a line-end sequence * before the dashed boundary string. * * Return the offset to the 1st byte of the boundary delimiter line. * Set boundary_line_len to the length of the entire boundary delimiter. * Set last_boundary to TRUE if we've seen the last-boundary delimiter. */ static gint find_next_boundary(tvbuff_t *tvb, gint start, const guint8 *boundary, gint boundary_len, gint *boundary_line_len, gboolean *last_boundary) { gint offset = start, next_offset, line_len, boundary_start; while (tvb_length_remaining(tvb, offset + 2 + boundary_len) > 0) { line_len = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); if (line_len == -1) { return -1; } boundary_start = offset + line_len; if (((tvb_strneql(tvb, next_offset, (const guint8 *)"--", 2) == 0) && (tvb_strneql(tvb, next_offset + 2, boundary, boundary_len) == 0))) { /* Boundary string; now check if last */ if ((tvb_length_remaining(tvb, next_offset + 2 + boundary_len + 2) >= 0) && (tvb_strneql(tvb, next_offset + 2 + boundary_len, (const guint8 *)"--", 2) == 0)) { *last_boundary = TRUE; } else { *last_boundary = FALSE; } /* Look for line end of the boundary line */ line_len = tvb_find_line_end(tvb, next_offset, -1, &offset, FALSE); if (line_len == -1) { *boundary_line_len = -1; } else { *boundary_line_len = offset - boundary_start; } return boundary_start; } offset = next_offset; } return -1; }
/* ABNF of line-end: * end-line = "-------" transact-id continuation-flag CRLF * This code is modeled on the code in packet-multipart.c */ static int find_end_line(tvbuff_t *tvb, gint start) { gint offset = start, next_offset, linelen; while (tvb_length_remaining(tvb, offset) > 0) { /* 'desegment' is FALSE so will set next_offset to beyond the end of the buffer if no line ending is found */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); if (linelen == -1) { return -1; } if (tvb_strneql(tvb, next_offset, (const gchar *)"-------", 7) == 0) return next_offset; offset = next_offset; } return -1; }
static int cond_string(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) { int len = wanted->len; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) g_warning("cond_string: control='%s'",wanted->control.str); #endif if ( offset + wanted->len > tt->end_offset ) return -1; if ( tvb_strneql(tt->tvb, offset, wanted->control.str, len) == 0 ) { *tok = new_tok(tt,wanted->id,offset,len,wanted); #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) g_warning("cond_string: GOT len=%i",len); #endif return len; } else { return -1; } }
/* * Unless the first boundary, subsequent boundaries include a line-end sequence * before the dashed boundary string. * * Return the offset to the 1st byte of the boundary delimiter line. * Set boundary_line_len to the length of the entire boundary delimiter. * Set last_boundary to TRUE if we've seen the last-boundary delimiter. */ static gint find_next_boundary(tvbuff_t *tvb, gint start, const guint8 *boundary, gint boundary_len, gint *boundary_line_len, gboolean *last_boundary) { gint offset = start, next_offset, line_len, boundary_start; while (tvb_offset_exists(tvb, offset + 2 + boundary_len)) { line_len = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); if (line_len == -1) { return -1; } boundary_start = offset + line_len; if (((tvb_strneql(tvb, next_offset, (const guint8 *)"--", 2) == 0) && (tvb_strneql(tvb, next_offset + 2, boundary, boundary_len) == 0))) { /* Boundary string; now check if last */ if ((tvb_reported_length_remaining(tvb, next_offset + 2 + boundary_len + 2) >= 0) && (tvb_strneql(tvb, next_offset + 2 + boundary_len, (const guint8 *)"--", 2) == 0)) { *last_boundary = TRUE; } else { *last_boundary = FALSE; } /* Look for line end of the boundary line */ line_len = tvb_find_line_end(tvb, next_offset, -1, &offset, FALSE); if (line_len == -1) { *boundary_line_len = -1; } else { *boundary_line_len = offset - boundary_start; } return boundary_start; /* check if last before CRLF; some ignore the standard, so there is no CRLF before the boundary */ } else if ((tvb_strneql(tvb, boundary_start - 2, (const guint8 *)"--", 2) == 0) && (tvb_strneql(tvb, boundary_start - (2 + boundary_len), boundary, boundary_len) == 0) && (tvb_strneql(tvb, boundary_start - (2 + boundary_len + 2), (const guint8 *)"--", 2) == 0)) { boundary_start -= 2 + boundary_len + 2; *boundary_line_len = next_offset - boundary_start; *last_boundary = TRUE; return boundary_start; } offset = next_offset; } return -1; }
static int fix_marker(tvbuff_t *tvb, int offset) { return tvb_strneql(tvb, offset, MARKER_TAG, MARKER_LEN); }
static void dissect_sap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 0; int sap_version, is_ipv6, is_del, is_enc, is_comp, addr_len; guint8 vers_flags; guint8 auth_len; guint16 tmp1; guint8 auth_flags; tvbuff_t *next_tvb; proto_item *si, *sif; proto_tree *sap_tree, *sap_flags_tree; col_set_str(pinfo->cinfo, COL_PROTOCOL, "SAP"); col_clear(pinfo->cinfo, COL_INFO); vers_flags = tvb_get_guint8(tvb, offset); is_ipv6 = vers_flags&MCAST_SAP_BIT_A; is_del = vers_flags&MCAST_SAP_BIT_T; is_enc = vers_flags&MCAST_SAP_BIT_E; is_comp = vers_flags&MCAST_SAP_BIT_C; sap_version = (vers_flags&MCAST_SAP_VERSION_MASK)>>MCAST_SAP_VERSION_SHIFT; addr_len = (is_ipv6) ? sizeof(struct e_in6_addr) : 4; if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "%s (v%u)", (is_del) ? "Deletion" : "Announcement", sap_version); } if (tree) { si = proto_tree_add_item(tree, proto_sap, tvb, offset, -1, ENC_NA); sap_tree = proto_item_add_subtree(si, ett_sap); sif = proto_tree_add_uint(sap_tree, hf_sap_flags, tvb, offset, 1, vers_flags); sap_flags_tree = proto_item_add_subtree(sif, ett_sap_flags); proto_tree_add_uint(sap_flags_tree, hf_sap_flags_v, tvb, offset, 1, vers_flags); proto_tree_add_boolean(sap_flags_tree, hf_sap_flags_a, tvb, offset, 1, vers_flags); proto_tree_add_boolean(sap_flags_tree, hf_sap_flags_r, tvb, offset, 1, vers_flags); proto_tree_add_boolean(sap_flags_tree, hf_sap_flags_t, tvb, offset, 1, vers_flags); proto_tree_add_boolean(sap_flags_tree, hf_sap_flags_e, tvb, offset, 1, vers_flags); proto_tree_add_boolean(sap_flags_tree, hf_sap_flags_c, tvb, offset, 1, vers_flags); offset++; auth_len = tvb_get_guint8(tvb, offset); proto_tree_add_text(sap_tree, tvb, offset, 1, "Authentication Length: %u", auth_len); offset++; tmp1 = tvb_get_ntohs(tvb, offset); proto_tree_add_text(sap_tree, tvb, offset, 2, "Message Identifier Hash: 0x%x", tmp1); offset +=2; proto_tree_add_text(sap_tree, tvb, offset, addr_len, "Originating Source: %s", (is_ipv6) ? tvb_ip6_to_str(tvb, offset) : tvb_ip_to_str(tvb, offset)); offset += addr_len; /* Authentication data lives in its own subtree */ if (auth_len > 0) { guint32 auth_data_len; proto_item *sdi, *sai; proto_tree *sa_tree, *saf_tree; int has_pad; guint8 pad_len = 0; auth_data_len = auth_len * sizeof(guint32); sdi = proto_tree_add_item(sap_tree, hf_auth_data, tvb, offset, auth_data_len, ENC_NA); sa_tree = proto_item_add_subtree(sdi, ett_sap_auth); auth_flags = tvb_get_guint8(tvb, offset); sai = proto_tree_add_uint(sa_tree, hf_auth_flags, tvb, offset, 1, auth_flags); saf_tree = proto_item_add_subtree(sai, ett_sap_authf); proto_tree_add_uint(saf_tree, hf_auth_flags_v, tvb, offset, 1, auth_flags); proto_tree_add_boolean(saf_tree, hf_auth_flags_p, tvb, offset, 1, auth_flags); proto_tree_add_uint(saf_tree, hf_auth_flags_t, tvb, offset, 1, auth_flags); has_pad = auth_flags&MCAST_SAP_AUTH_BIT_P; if (has_pad) pad_len = tvb_get_guint8(tvb, offset+auth_data_len-1); if ((int) auth_data_len - pad_len - 1 < 0) { proto_tree_add_text(sa_tree, tvb, 0, 0, "Bogus authentication length (%d) or pad length (%d)", auth_len, pad_len); return; } proto_tree_add_text(sa_tree, tvb, offset+1, auth_data_len-pad_len-1, "Authentication subheader: (%u byte%s)", auth_data_len-1, plurality(auth_data_len-1, "", "s")); if (has_pad) { proto_tree_add_text(sa_tree, tvb, offset+auth_data_len-pad_len, pad_len, "Authentication data padding: (%u byte%s)", pad_len, plurality(pad_len, "", "s")); proto_tree_add_text(sa_tree, tvb, offset+auth_data_len-1, 1, "Authentication data pad count: %u byte%s", pad_len, plurality(pad_len, "", "s")); } offset += auth_data_len; } if (is_enc || is_comp) { const char *mangle; if (is_enc && is_comp) mangle = "compressed and encrypted"; else if (is_enc) mangle = "encrypted"; else mangle = "compressed"; proto_tree_add_text(sap_tree, tvb, offset, -1, "The rest of the packet is %s", mangle); return; } /* Do we have the optional payload type aka. MIME content specifier */ if (tvb_strneql(tvb, offset, "v=", strlen("v="))) { gint remaining_len; guint32 pt_len; int pt_string_len; remaining_len = tvb_length_remaining(tvb, offset); if (remaining_len == 0) { /* * "tvb_strneql()" failed because there was no * data left in the packet. * * Set the remaining length to 1, so that * we throw the appropriate exception in * "tvb_get_ptr()", rather than displaying * the payload type. */ remaining_len = 1; } pt_string_len = tvb_strnlen(tvb, offset, remaining_len); if (pt_string_len == -1) { /* * We didn't find a terminating '\0'; run to the * end of the buffer. */ pt_string_len = remaining_len; pt_len = pt_string_len; } else { /* * Include the '\0' in the total item length. */ pt_len = pt_string_len + 1; } proto_tree_add_text(sap_tree, tvb, offset, pt_len, "Payload type: %.*s", pt_string_len, tvb_get_ephemeral_string(tvb, offset, pt_string_len)); offset += pt_len; } } /* Done with SAP */ next_tvb = tvb_new_subset_remaining(tvb, offset); call_dissector(sdp_handle, next_tvb, pinfo, tree); return; }
/* Dissect OSC bundle */ static int dissect_osc_bundle(tvbuff_t *tvb, proto_item *ti, proto_tree *osc_tree, gint offset, gint len) { proto_tree *bundle_tree; gint end = offset + len; guint32 sec; guint32 frac; nstime_t ns; /* check for valid #bundle */ if(tvb_strneql(tvb, offset, bundle_str, 8) != 0) return -1; /* create bundle */ ti = proto_tree_add_item(osc_tree, hf_osc_bundle_type, tvb, offset, len, ENC_NA); bundle_tree = proto_item_add_subtree(ti, ett_osc_bundle); offset += 8; /* skip bundle_str */ /* read timetag */ sec = tvb_get_ntohl(tvb, offset); frac = tvb_get_ntohl(tvb, offset+4); if( (sec == 0) && (frac == 1) ) proto_tree_add_time_format_value(bundle_tree, hf_osc_bundle_timetag_type, tvb, offset, 8, &ns, immediate_fmt, immediate_str); else proto_tree_add_item(bundle_tree, hf_osc_bundle_timetag_type, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN); offset += 8; /* ::read size, read block:: */ while(offset < end) { /* peek bundle element size */ gint32 size = tvb_get_ntohl(tvb, offset); /* read bundle element size */ proto_tree_add_int_format_value(bundle_tree, hf_osc_bundle_element_size_type, tvb, offset, 4, size, "%i bytes", size); offset += 4; /* check for zero size bundle element */ if(size == 0) continue; /* peek first bundle element char */ switch(tvb_get_guint8(tvb, offset)) { case '#': /* this is a bundle */ if(dissect_osc_bundle(tvb, ti, bundle_tree, offset, size)) return -1; else break; case '/': /* this is a message */ if(dissect_osc_message(tvb, ti, bundle_tree, offset, size)) return -1; else break; default: return -1; /* neither message nor bundle */ } /* check for integer overflow */ if(size > G_MAXINT - offset) return -1; else offset += size; } if(offset != end) return -1; else return 0; }
static void dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { struct smtp_proto_data *spd_frame_data; proto_tree *smtp_tree = NULL; proto_tree *cmdresp_tree; proto_item *ti, *hidden_item; int offset = 0; int request = 0; conversation_t *conversation; struct smtp_session_state *session_state; const guchar *line, *linep, *lineend; guint32 code; int linelen = 0; gint length_remaining; gboolean eom_seen = FALSE; gint next_offset; gint loffset = 0; int cmdlen; fragment_data *frag_msg = NULL; tvbuff_t *next_tvb; /* As there is no guarantee that we will only see frames in the * the SMTP conversation once, and that we will see them in * order - in Wireshark, the user could randomly click on frames * in the conversation in any order in which they choose - we * have to store information with each frame indicating whether * it contains commands or data or an EOM indication. * * XXX - what about frames that contain *both*? TCP is a * byte-stream protocol, and there are no guarantees that * TCP segment boundaries will correspond to SMTP commands * or EOM indications. * * We only need that for the client->server stream; responses * are easy to manage. * * If we have per frame data, use that, else, we must be on the first * pass, so we figure it out on the first pass. */ /* * Find or create the conversation for this. */ conversation = find_or_create_conversation(pinfo); /* * Is there a request structure attached to this conversation? */ session_state = conversation_get_proto_data(conversation, proto_smtp); if (!session_state) { /* * No - create one and attach it. */ session_state = se_alloc(sizeof(struct smtp_session_state)); session_state->smtp_state = SMTP_STATE_READING_CMDS; session_state->crlf_seen = FALSE; session_state->data_seen = FALSE; session_state->msg_read_len = 0; session_state->msg_tot_len = 0; session_state->msg_last = TRUE; session_state->last_nontls_frame = 0; conversation_add_proto_data(conversation, proto_smtp, session_state); } /* Are we doing TLS? * FIXME In my understanding of RFC 2487 client and server can send SMTP cmds * after a rejected TLS negotiation */ if (session_state->last_nontls_frame != 0 && pinfo->fd->num > session_state->last_nontls_frame) { guint16 save_can_desegment; guint32 save_last_nontls_frame; /* This is TLS, not raw SMTP. TLS can desegment */ save_can_desegment = pinfo->can_desegment; pinfo->can_desegment = pinfo->saved_can_desegment; /* Make sure the SSL dissector will not be called again after decryption */ save_last_nontls_frame = session_state->last_nontls_frame; session_state->last_nontls_frame = 0; call_dissector(ssl_handle, tvb, pinfo, tree); pinfo->can_desegment = save_can_desegment; session_state->last_nontls_frame = save_last_nontls_frame; return; } /* Is this a request or a response? */ request = pinfo->destport == pinfo->match_uint; /* * Is there any data attached to this frame? */ spd_frame_data = p_get_proto_data(pinfo->fd, proto_smtp); if (!spd_frame_data) { /* * No frame data. */ if(request) { /* * Create a frame data structure and attach it to the packet. */ spd_frame_data = se_alloc0(sizeof(struct smtp_proto_data)); spd_frame_data->conversation_id = conversation->index; spd_frame_data->more_frags = TRUE; p_add_proto_data(pinfo->fd, proto_smtp, spd_frame_data); } /* * Get the first line from the buffer. * * Note that "tvb_find_line_end()" will, if it doesn't return * -1, return a value that is not longer than what's in the buffer, * and "tvb_find_line_end()" will always return a value that is not * longer than what's in the buffer, so the "tvb_get_ptr()" call * won't throw an exception. */ loffset = offset; while (tvb_offset_exists(tvb, loffset)) { linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset, smtp_desegment && pinfo->can_desegment); if (linelen == -1) { if (offset == loffset) { /* * We didn't find a line ending, and we're doing desegmentation; * tell the TCP dissector where the data for this message starts * in the data it handed us, and tell it we need more bytes */ pinfo->desegment_offset = loffset; pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; return; } else { linelen = tvb_length_remaining(tvb, loffset); next_offset = loffset + linelen; } } line = tvb_get_ptr(tvb, loffset, linelen); /* * Check whether or not this packet is an end of message packet * We should look for CRLF.CRLF and they may be split. * We have to keep in mind that we may see what we want on * two passes through here ... */ if (session_state->smtp_state == SMTP_STATE_READING_DATA) { /* * The order of these is important ... We want to avoid * cases where there is a CRLF at the end of a packet and a * .CRLF at the begining of the same packet. */ if ((session_state->crlf_seen && tvb_strneql(tvb, loffset, ".\r\n", 3) == 0) || tvb_strneql(tvb, loffset, "\r\n.\r\n", 5) == 0) eom_seen = TRUE; length_remaining = tvb_length_remaining(tvb, loffset); if (length_remaining == tvb_reported_length_remaining(tvb, loffset) && tvb_strneql(tvb, loffset + length_remaining - 2, "\r\n", 2) == 0) session_state->crlf_seen = TRUE; else session_state->crlf_seen = FALSE; } /* * OK, Check if we have seen a DATA request. We do it here for * simplicity, but we have to be careful below. */ if (request) { if (session_state->smtp_state == SMTP_STATE_READING_DATA) { /* * This is message data. */ if (eom_seen) { /* Seen the EOM */ /* * EOM. * Everything that comes after it is commands. */ spd_frame_data->pdu_type = SMTP_PDU_EOM; session_state->smtp_state = SMTP_STATE_READING_CMDS; break; } else { /* * Message data with no EOM. */ spd_frame_data->pdu_type = SMTP_PDU_MESSAGE; if (session_state->msg_tot_len > 0) { /* * We are handling a BDAT message. * Check if we have reached end of the data chunk. */ session_state->msg_read_len += tvb_length_remaining(tvb, loffset); if (session_state->msg_read_len == session_state->msg_tot_len) { /* * We have reached end of BDAT data chunk. * Everything that comes after this is commands. */ session_state->smtp_state = SMTP_STATE_READING_CMDS; if (session_state->msg_last) { /* * We have found the LAST data chunk. * The message can now be reassembled. */ spd_frame_data->more_frags = FALSE; } break; /* no need to go through the remaining lines */ } } } } else { /* * This is commands - unless the capture started in the * middle of a session, and we're in the middle of data. * * Commands are not necessarily 4 characters; look * for a space or the end of the line to see where * the putative command ends. */ linep = line; lineend = line + linelen; while (linep < lineend && *linep != ' ') linep++; cmdlen = (int)(linep - line); if (line_is_smtp_command(line, cmdlen)) { if (g_ascii_strncasecmp(line, "DATA", 4) == 0) { /* * DATA command. * This is a command, but everything that comes after it, * until an EOM, is data. */ spd_frame_data->pdu_type = SMTP_PDU_CMD; session_state->smtp_state = SMTP_STATE_READING_DATA; session_state->data_seen = TRUE; } else if (g_ascii_strncasecmp(line, "BDAT", 4) == 0) { /* * BDAT command. * This is a command, but everything that comes after it, * until given length is received, is data. */ guint32 msg_len; msg_len = strtoul (line+5, NULL, 10); spd_frame_data->pdu_type = SMTP_PDU_CMD; session_state->data_seen = TRUE; session_state->msg_tot_len += msg_len; if (msg_len == 0) { /* No data to read, next will be a command */ session_state->smtp_state = SMTP_STATE_READING_CMDS; } else { session_state->smtp_state = SMTP_STATE_READING_DATA; } if (g_ascii_strncasecmp(line+linelen-4, "LAST", 4) == 0) { /* * This is the last data chunk. */ session_state->msg_last = TRUE; if (msg_len == 0) { /* * No more data to expect. * The message can now be reassembled. */ spd_frame_data->more_frags = FALSE; } } else { session_state->msg_last = FALSE; } } else if (g_ascii_strncasecmp(line, "STARTTLS", 8) == 0) { /* * STARTTLS command. * This is a command, but if the response is 220, * everything after the response is TLS. */ session_state->smtp_state = SMTP_STATE_AWAITING_STARTTLS_RESPONSE; spd_frame_data->pdu_type = SMTP_PDU_CMD; } else { /* * Regular command. */ spd_frame_data->pdu_type = SMTP_PDU_CMD; } } else { /* * Assume it's message data. */ spd_frame_data->pdu_type = session_state->data_seen ? SMTP_PDU_MESSAGE : SMTP_PDU_CMD; } } } /* * Step past this line. */ loffset = next_offset; } } /* * From here, we simply add items to the tree and info to the info * fields ... */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMTP"); if (check_col(pinfo->cinfo, COL_INFO)) { /* Add the appropriate type here */ col_clear(pinfo->cinfo, COL_INFO); /* * If it is a request, we have to look things up, otherwise, just * display the right things */ if (request) { /* We must have frame_data here ... */ switch (spd_frame_data->pdu_type) { case SMTP_PDU_MESSAGE: length_remaining = tvb_length_remaining(tvb, offset); col_set_str(pinfo->cinfo, COL_INFO, smtp_data_desegment ? "C: DATA fragment" : "C: Message Body"); col_append_fstr(pinfo->cinfo, COL_INFO, ", %d byte%s", length_remaining, plurality (length_remaining, "", "s")); break; case SMTP_PDU_EOM: col_set_str(pinfo->cinfo, COL_INFO, "C: ."); break; case SMTP_PDU_CMD: loffset = offset; while (tvb_offset_exists(tvb, loffset)) { /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, loffset, linelen); if(loffset == offset) col_append_fstr(pinfo->cinfo, COL_INFO, "C: %s", format_text(line, linelen)); else { col_append_fstr(pinfo->cinfo, COL_INFO, " | %s", format_text(line, linelen)); } loffset = next_offset; } break; } } else { loffset = offset; while (tvb_offset_exists(tvb, loffset)) { /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, loffset, linelen); if (loffset == offset) col_append_fstr(pinfo->cinfo, COL_INFO, "S: %s", format_text(line, linelen)); else { col_append_fstr(pinfo->cinfo, COL_INFO, " | %s", format_text(line, linelen)); } loffset = next_offset; } } } if (tree) { /* Build the tree info ... */ ti = proto_tree_add_item(tree, proto_smtp, tvb, offset, -1, ENC_NA); smtp_tree = proto_item_add_subtree(ti, ett_smtp); } if (request) { /* * Check out whether or not we can see a command in there ... * What we are looking for is not data_seen and the word DATA * and not eom_seen. * * We will see DATA and session_state->data_seen when we process the * tree view after we have seen a DATA packet when processing * the packet list pane. * * On the first pass, we will not have any info on the packets * On second and subsequent passes, we will. */ switch (spd_frame_data->pdu_type) { case SMTP_PDU_MESSAGE: if (smtp_data_desegment) { frag_msg = fragment_add_seq_next(tvb, 0, pinfo, spd_frame_data->conversation_id, smtp_data_segment_table, smtp_data_reassembled_table, tvb_length(tvb), spd_frame_data->more_frags); } else { /* * Message body. * Put its lines into the protocol tree, a line at a time. */ dissect_smtp_data(tvb, offset, smtp_tree); } break; case SMTP_PDU_EOM: /* * End-of-message-body indicator. * * XXX - what about stuff after the first line? * Unlikely, as the client should wait for a response to the * DATA command this terminates before sending another * request, but we should probably handle it. */ proto_tree_add_text(smtp_tree, tvb, offset, linelen, "C: ."); if (smtp_data_desegment) { /* add final data segment */ if (loffset) fragment_add_seq_next(tvb, 0, pinfo, spd_frame_data->conversation_id, smtp_data_segment_table, smtp_data_reassembled_table, loffset, spd_frame_data->more_frags); /* terminate the desegmentation */ frag_msg = fragment_end_seq_next (pinfo, spd_frame_data->conversation_id, smtp_data_segment_table, smtp_data_reassembled_table); } break; case SMTP_PDU_CMD: /* * Command. * * XXX - what about stuff after the first line? * Unlikely, as the client should wait for a response to the * previous command before sending another request, but we * should probably handle it. */ loffset = offset; while (tvb_offset_exists(tvb, loffset)) { /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset, FALSE); if (linelen >= 4) cmdlen = 4; else cmdlen = linelen; hidden_item = proto_tree_add_boolean(smtp_tree, hf_smtp_req, tvb, 0, 0, TRUE); PROTO_ITEM_SET_HIDDEN(hidden_item); /* * Put the command line into the protocol tree. */ ti = proto_tree_add_item(smtp_tree, hf_smtp_command_line, tvb, loffset, next_offset - loffset, ENC_ASCII|ENC_NA); cmdresp_tree = proto_item_add_subtree(ti, ett_smtp_cmdresp); proto_tree_add_item(cmdresp_tree, hf_smtp_req_command, tvb, loffset, cmdlen, ENC_ASCII|ENC_NA); if (linelen > 5) { proto_tree_add_item(cmdresp_tree, hf_smtp_req_parameter, tvb, loffset + 5, linelen - 5, ENC_ASCII|ENC_NA); } if (smtp_data_desegment && !spd_frame_data->more_frags) { /* terminate the desegmentation */ frag_msg = fragment_end_seq_next (pinfo, spd_frame_data->conversation_id, smtp_data_segment_table, smtp_data_reassembled_table); } /* * Step past this line. */ loffset = next_offset; } } if (smtp_data_desegment) { next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled SMTP", frag_msg, &smtp_data_frag_items, NULL, smtp_tree); if (next_tvb) { /* XXX: this is presumptious - we may have negotiated something else */ if (imf_handle) { call_dissector(imf_handle, next_tvb, pinfo, tree); } else { /* * Message body. * Put its lines into the protocol tree, a line at a time. */ dissect_smtp_data(tvb, offset, smtp_tree); } pinfo->fragmented = FALSE; } else { pinfo->fragmented = TRUE; } } } else { /* * Process the response, a line at a time, until we hit a line * that doesn't have a continuation indication on it. */ if (tree) { hidden_item = proto_tree_add_boolean(smtp_tree, hf_smtp_rsp, tvb, 0, 0, TRUE); PROTO_ITEM_SET_HIDDEN(hidden_item); } while (tvb_offset_exists(tvb, offset)) { /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); if (tree) { /* * Put it into the protocol tree. */ ti = proto_tree_add_item(smtp_tree, hf_smtp_response, tvb, offset, next_offset - offset, ENC_ASCII|ENC_NA); cmdresp_tree = proto_item_add_subtree(ti, ett_smtp_cmdresp); } else cmdresp_tree = NULL; line = tvb_get_ptr(tvb, offset, linelen); if (linelen >= 3 && isdigit(line[0]) && isdigit(line[1]) && isdigit(line[2])) { /* * We have a 3-digit response code. */ code = (line[0] - '0')*100 + (line[1] - '0')*10 + (line[2] - '0'); /* * If we're awaiting the response to a STARTTLS code, this * is it - if it's 220, all subsequent traffic will * be TLS, otherwise we're back to boring old SMTP. */ if (session_state->smtp_state == SMTP_STATE_AWAITING_STARTTLS_RESPONSE) { if (code == 220) { /* This is the last non-TLS frame. */ session_state->last_nontls_frame = pinfo->fd->num; } session_state->smtp_state = SMTP_STATE_READING_CMDS; } if (tree) { /* * Put the response code and parameters into the protocol tree. */ proto_tree_add_uint(cmdresp_tree, hf_smtp_rsp_code, tvb, offset, 3, code); if (linelen >= 4) { proto_tree_add_item(cmdresp_tree, hf_smtp_rsp_parameter, tvb, offset + 4, linelen - 4, ENC_ASCII|ENC_NA); } } } /* * Step past this line. */ offset = next_offset; } } }
static gboolean dissect_clique_rm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint8 version = 0; guint8 type = 0; int offset = 0; if (tvb_length (tvb) < 12) return FALSE; if (tvb_strneql (tvb, offset, "Clique", 6)) return FALSE; offset += 6; version = tvb_get_guint8 (tvb, offset); if (version != 1) return FALSE; offset++; type = tvb_get_guint8 (tvb, offset); offset++; col_set_str(pinfo->cinfo, COL_PROTOCOL, "Clique-rm"); col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(type, packet_type_vals, "Unknown (0x%02x)")); if (tree) { proto_item *ti = NULL; proto_tree *clique_rm_tree = NULL; /* rewind back to just behind the prefix */ offset = 6; ti = proto_tree_add_item(tree, proto_clique_rm, tvb, 0, -1, ENC_NA); clique_rm_tree = proto_item_add_subtree(ti, ett_clique_rm); proto_tree_add_item(clique_rm_tree, hf_clique_rm_version, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(clique_rm_tree, hf_clique_rm_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", sender: 0x%x", tvb_get_ntohl (tvb, offset)); proto_tree_add_item(clique_rm_tree, hf_clique_rm_sender, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; if (IS_RELIABLE(type)) { if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", id: 0x%x", tvb_get_ntohl (tvb, offset)); dissect_reliable_packet(clique_rm_tree, type, tvb, offset); } else { dissect_unreliable_packet(clique_rm_tree, type, tvb, offset); } } return TRUE; }
static int dissect_beep_tree(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, struct beep_request_val *request_val, struct beep_proto_data *beep_frame_data) { proto_tree *ti = NULL, *hdr = NULL; /*proto_item *hidden_item;*/ int st_offset, msgno, ansno, seqno, size, channel, ackno, window, cc, more; const char * cmd_temp = NULL; int is_ANS = 0; st_offset = offset; if (tvb_strneql(tvb, offset, "MSG ", 4) == 0) cmd_temp = "Command: MSG"; if (tvb_strneql(tvb, offset, "RPY ", 4) == 0) cmd_temp = "Command: RPY"; if (tvb_strneql(tvb, offset, "ERR ", 4) == 0) cmd_temp = "Command: ERR"; if (tvb_strneql(tvb, offset, "NUL ", 4) == 0) cmd_temp = "Command: NUL"; if (tvb_strneql(tvb, offset, "ANS ", 4) == 0) { cmd_temp = "Command: ANS"; is_ANS = 1; } if (cmd_temp != NULL) { if (tree) { hdr = proto_tree_add_subtree(tree, tvb, offset, header_len(tvb, offset) + 2, ett_header, NULL, "Header"); ti = proto_tree_add_item(hdr, hf_beep_cmd, tvb, offset, 3, ENC_NA|ENC_ASCII); /* Include space */ proto_item_set_len(ti, 4); proto_tree_add_boolean(hdr, hf_beep_req, tvb, offset, 3, TRUE); } offset += 4; /* Get the channel */ offset += dissect_beep_int(tvb, offset, hdr, hf_beep_channel, &channel, req_chan_hfa); offset += 1; /* Skip the space */ /* Dissect the message number */ offset += dissect_beep_int(tvb, offset, hdr, hf_beep_msgno, &msgno, req_msgno_hfa); offset += 1; /* skip the space */ /* Insert the more elements ... */ if ((more = dissect_beep_more(tvb, pinfo, offset, hdr)) >= 0) { /* Figure out which direction this is in and what mime_hdr flag to * add to the beep_frame_data. If there are missing segments, this code * will get it wrong! */ set_mime_hdr_flags(more, request_val, beep_frame_data, pinfo); } else { /* Protocol violation, so dissect rest as undisectable */ if (tree && (tvb_length_remaining(tvb, offset) > 0)) { proto_tree_add_item(tree, hf_beep_payload_undissected, tvb, offset, tvb_length_remaining(tvb, offset), ENC_NA|ENC_ASCII); } return -1; } offset += 2; /* Skip the flag and the space ... */ /* now for the seqno */ offset += dissect_beep_int(tvb, offset, hdr, hf_beep_seqno, &seqno, req_seqno_hfa); offset += 1; /* skip the space */ offset += dissect_beep_int(tvb, offset, hdr, hf_beep_size, &size, req_size_hfa); if (request_val) /* FIXME, is this the right order ... */ request_val -> size = size; /* Stash this away */ else if (beep_frame_data) { beep_frame_data->pl_size = size; if (beep_frame_data->pl_size < 0) beep_frame_data->pl_size = 0; /* FIXME: OK? */ } /* offset += 1; skip the space */ if (is_ANS) { /* We need to put in the ansno */ offset += 1; /* skip the space */ /* Dissect the message number */ offset += dissect_beep_int(tvb, offset, hdr, hf_beep_ansno, &ansno, req_ansno_hfa); } if ((cc = check_term(tvb, pinfo, offset, hdr)) <= 0) { /* We dissect the rest as data and bail ... */ if (tree && (tvb_length_remaining(tvb, offset) > 0)) { proto_tree_add_item(tree, hf_beep_payload_undissected, tvb, offset, tvb_length_remaining(tvb, offset), ENC_NA|ENC_ASCII); } return -1; } offset += cc; /* Insert MIME header ... */ if (beep_frame_data && beep_frame_data->mime_hdr) offset += dissect_beep_mime_header(tvb, pinfo, offset, beep_frame_data, hdr); /* Now for the payload, if any */ if (tvb_length_remaining(tvb, offset) > 0) { /* Dissect what is left as payload */ int pl_size = MIN(size, tvb_length_remaining(tvb, offset)); /* Except, check the payload length, and only dissect that much */ /* We need to keep track, in the conversation, of how much is left * so in the next packet, we can figure out what is part of the payload * and what is the next message */ if (tree) { proto_tree_add_item(tree, hf_beep_payload, tvb, offset, pl_size, ENC_NA|ENC_ASCII); } offset += pl_size; if (request_val) { request_val->size -= pl_size; if (request_val->size < 0) request_val->size = 0; } else if (beep_frame_data) { beep_frame_data->pl_size -= pl_size; if (beep_frame_data->pl_size < 0) beep_frame_data->pl_size = 0; } } /* If anything else left, dissect it ... */ if (tvb_length_remaining(tvb, offset) > 0) offset += dissect_beep_tree(tvb, offset, pinfo, tree, request_val, beep_frame_data); } else if (tvb_strneql(tvb, offset, "SEQ ", 4) == 0) { if (tree) { ti = proto_tree_add_item(hdr, hf_beep_cmd, tvb, offset, 3, ENC_NA|ENC_ASCII); /* Include space */ proto_item_set_len(ti, 4); } offset += 3; /* Now check the space: FIXME */ offset += 1; offset += dissect_beep_int(tvb, offset, tree, hf_beep_channel, &channel, seq_chan_hfa); /* Check the space: FIXME */ offset += 1; offset += dissect_beep_int(tvb, offset, tree, hf_beep_ackno, &ackno, seq_ackno_hfa); /* Check the space: FIXME */ offset += 1; offset += dissect_beep_int(tvb, offset, tree, hf_beep_window, &window, seq_window_hfa); if ((cc = check_term(tvb, pinfo, offset, tree)) <= 0) { /* We dissect the rest as data and bail ... */ if (tree && (tvb_length_remaining(tvb, offset) > 0)) { proto_tree_add_item(tree, hf_beep_payload_undissected, tvb, offset, tvb_length_remaining(tvb, offset), ENC_NA|ENC_ASCII); } return -1; } offset += cc; } else if (tvb_strneql(tvb, offset, "END", 3) == 0) { proto_tree *tr = NULL; if (tree) { tr = proto_tree_add_subtree(tree, tvb, offset, MIN(5, MAX(0, tvb_length_remaining(tvb, offset))), ett_trailer, NULL, "Trailer"); proto_tree_add_item(hdr, hf_beep_cmd, tvb, offset, 3, ENC_NA|ENC_ASCII); } offset += 3; if ((cc = check_term(tvb, pinfo, offset, tr)) <= 0) { /* We dissect the rest as data and bail ... */ if (tree && (tvb_length_remaining(tvb, offset) > 0)) { proto_tree_add_item(tree, hf_beep_payload_undissected, tvb, offset, tvb_length_remaining(tvb, offset), ENC_NA|ENC_ASCII); } return -1; } offset += cc; } if (tvb_length_remaining(tvb, offset) > 0) { /* Dissect anything left over */ int pl_size = 0; if (request_val) { pl_size = MIN(request_val->size, tvb_length_remaining(tvb, offset)); if (pl_size == 0) { /* The whole of the rest must be payload */ pl_size = tvb_length_remaining(tvb, offset); /* Right place ? */ } } else if (beep_frame_data) { pl_size = MIN(beep_frame_data->pl_size, tvb_length_remaining(tvb, offset)); } else { /* Just in case */ pl_size = tvb_length_remaining(tvb, offset); } /* Take care here to handle the payload correctly, and if there is * another message here, then handle it correctly as well. */ /* If the pl_size == 0 and the offset == 0?, then we have not processed * anything in this frame above, so we better treat all this data as * payload to avoid recursion loops */ if (pl_size == 0 && offset == st_offset) pl_size = tvb_length_remaining(tvb, offset); if (pl_size > 0) { if (tree) { proto_tree_add_item(tree, hf_beep_payload, tvb, offset, pl_size, ENC_NA|ENC_ASCII); } offset += pl_size; /* Advance past the payload */ if (request_val){ request_val->size -= pl_size; /* Reduce payload by what we added */ if (request_val->size < 0) request_val->size = 0; } else if (beep_frame_data) { beep_frame_data->pl_size -= pl_size; if (beep_frame_data->pl_size < 0) beep_frame_data->pl_size = 0; } } if (tvb_length_remaining(tvb, offset) > 0) { offset += dissect_beep_tree(tvb, offset, pinfo, tree, request_val, beep_frame_data); } } return offset - st_offset; }
static int dissect_gssapi_work(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_verifier) { proto_item *volatile item; proto_tree *volatile subtree; volatile int return_offset = 0; gssapi_conv_info_t *volatile gss_info; gssapi_oid_value *oidvalue; dissector_handle_t handle; conversation_t *conversation; tvbuff_t *oid_tvb; int len, start_offset, oid_start_offset; volatile int offset; gint8 appclass; gboolean pc, ind_field; gint32 tag; guint32 len1; const char *oid; fragment_data *fd_head=NULL; gssapi_frag_info_t *fi; tvbuff_t *volatile gss_tvb=NULL; asn1_ctx_t asn1_ctx; void *pd_save; start_offset=0; offset=0; asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo); /* * We don't know whether the data is encrypted, so say it's * not, for now. The subdissector must set gssapi_data_encrypted * if it is. */ pinfo->gssapi_data_encrypted = FALSE; /* * We need a conversation for later */ conversation = find_or_create_conversation(pinfo); gss_info = (gssapi_conv_info_t *)conversation_get_proto_data(conversation, proto_gssapi); if (!gss_info) { gss_info = se_new(gssapi_conv_info_t); gss_info->oid=NULL; gss_info->do_reassembly=FALSE; gss_info->frags=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "gssapi_frags"); conversation_add_proto_data(conversation, proto_gssapi, gss_info); } item = proto_tree_add_item( tree, proto_gssapi, tvb, offset, -1, ENC_NA); subtree = proto_item_add_subtree(item, ett_gssapi); /* * Catch the ReportedBoundsError exception; the stuff we've been * handed doesn't necessarily run to the end of the packet, it's * an item inside a packet, so if it happens to be malformed (or * we, or a dissector we call, has a bug), so that an exception * is thrown, we want to report the error, but return and let * our caller dissect the rest of the packet. * * If it gets a BoundsError, we can stop, as there's nothing more * in the packet after our blob to see, so we just re-throw the * exception. */ pd_save = pinfo->private_data; TRY { gss_tvb=tvb; /* First of all, if it's the first time we see this packet * then check whether we are in the middle of reassembly or not */ if( (!pinfo->fd->flags.visited) && (gss_info->do_reassembly) && (gssapi_reassembly) ){ fi=(gssapi_frag_info_t *)se_tree_lookup32(gss_info->frags, gss_info->first_frame); if(!fi){ goto done; } se_tree_insert32(gss_info->frags, pinfo->fd->num, fi); fd_head=fragment_add(&gssapi_reassembly_table, tvb, 0, pinfo, fi->first_frame, NULL, gss_info->frag_offset, tvb_length(tvb), TRUE); gss_info->frag_offset+=tvb_length(tvb); /* we need more fragments */ if(!fd_head){ goto done; } /* this blob is now fully reassembled */ gss_info->do_reassembly=FALSE; fi->reassembled_in=pinfo->fd->num; gss_tvb=tvb_new_child_real_data(tvb, fd_head->data, fd_head->datalen, fd_head->datalen); add_new_data_source(pinfo, gss_tvb, "Reassembled GSSAPI"); } /* We have seen this packet before. * Is this blob part of reassembly or a normal blob ? */ if( (pinfo->fd->flags.visited) && (gssapi_reassembly) ){ fi=(gssapi_frag_info_t *)se_tree_lookup32(gss_info->frags, pinfo->fd->num); if(fi){ fd_head=fragment_get(&gssapi_reassembly_table, pinfo, fi->first_frame, NULL); if(fd_head && (fd_head->flags&FD_DEFRAGMENTED)){ if(pinfo->fd->num==fi->reassembled_in){ proto_item *frag_tree_item; gss_tvb=tvb_new_child_real_data(tvb, fd_head->data, fd_head->datalen, fd_head->datalen); add_new_data_source(pinfo, gss_tvb, "Reassembled GSSAPI"); show_fragment_tree(fd_head, &gssapi_frag_items, tree, pinfo, tvb, &frag_tree_item); } else { proto_item *it; it=proto_tree_add_uint(tree, hf_gssapi_reassembled_in, tvb, 0, 0, fi->reassembled_in); PROTO_ITEM_SET_GENERATED(it); goto done; } } } } /* Read header */ offset = get_ber_identifier(gss_tvb, offset, &appclass, &pc, &tag); offset = get_ber_length(gss_tvb, offset, &len1, &ind_field); if (!(appclass == BER_CLASS_APP && pc && tag == 0)) { /* It could be NTLMSSP, with no OID. This can happen for anything that microsoft calls 'Negotiate' or GSS-SPNEGO */ if ((tvb_length_remaining(gss_tvb, start_offset)>7) && (tvb_strneql(gss_tvb, start_offset, "NTLMSSP", 7) == 0)) { return_offset = call_dissector(ntlmssp_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); goto done; } /* Maybe it's new NTLMSSP payload */ if ((tvb_length_remaining(gss_tvb, start_offset)>16) && ((tvb_memeql(gss_tvb, start_offset, "\x01\x00\x00\x00", 4) == 0))) { return_offset = call_dissector(ntlmssp_payload_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); pinfo->gssapi_data_encrypted = TRUE; goto done; } if ((tvb_length_remaining(gss_tvb, start_offset)==16) && ((tvb_memeql(gss_tvb, start_offset, "\x01\x00\x00\x00", 4) == 0))) { if( is_verifier ) { return_offset = call_dissector(ntlmssp_verf_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); } else if( pinfo->gssapi_encrypted_tvb ) { return_offset = call_dissector(ntlmssp_data_only_handle, tvb_new_subset_remaining(pinfo->gssapi_encrypted_tvb, 0), pinfo, subtree); pinfo->gssapi_data_encrypted = TRUE; } goto done; } /* Maybe it's new GSSKRB5 CFX Wrapping */ if ((tvb_length_remaining(gss_tvb, start_offset)>2) && ((tvb_memeql(gss_tvb, start_offset, "\04\x04", 2) == 0) || (tvb_memeql(gss_tvb, start_offset, "\05\x04", 2) == 0))) { return_offset = call_dissector(spnego_krb5_wrap_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); goto done; } /* * If we do not recognise an Application class, * then we are probably dealing with an inner context * token or a wrap token, and we should retrieve the * gssapi_oid_value pointer from the per-frame data or, * if there is no per-frame data (as would be the case * the first time we dissect this frame), from the * conversation that exists or that we created from * pinfo (and then make it per-frame data). * We need to make it per-frame data as there can be * more than one GSS-API negotiation in a conversation. * * Note! We "cheat". Since we only need the pointer, * we store that as the data. (That's not really * "cheating" - the per-frame data and per-conversation * data code doesn't care what you supply as a data * pointer; it just treats it as an opaque pointer, it * doesn't dereference it or free what it points to.) */ oidvalue = (gssapi_oid_value *)p_get_proto_data(pinfo->fd, proto_gssapi, 0); if (!oidvalue && !pinfo->fd->flags.visited) { /* No handle attached to this frame, but it's the first */ /* pass, so it'd be attached to the conversation. */ oidvalue = gss_info->oid; if (gss_info->oid) p_add_proto_data(pinfo->fd, proto_gssapi, 0, gss_info->oid); } if (!oidvalue) { proto_tree_add_text(subtree, gss_tvb, start_offset, 0, "Unknown header (class=%d, pc=%d, tag=%d)", appclass, pc, tag); return_offset = tvb_length(gss_tvb); goto done; } else { tvbuff_t *oid_tvb_local; oid_tvb_local = tvb_new_subset_remaining(gss_tvb, start_offset); if (is_verifier) handle = oidvalue->wrap_handle; else handle = oidvalue->handle; len = call_dissector(handle, oid_tvb_local, pinfo, subtree); if (len == 0) return_offset = tvb_length(gss_tvb); else return_offset = start_offset + len; goto done; /* We are finished here */ } } /* Read oid */ oid_start_offset=offset; offset=dissect_ber_object_identifier_str(FALSE, &asn1_ctx, subtree, gss_tvb, offset, hf_gssapi_oid, &oid); oidvalue = gssapi_lookup_oid_str(oid); /* Check if we need reassembly of this blob. * Only try reassembly for OIDs we recognize * and when we have the entire tvb * * SMB will sometimes split one large GSSAPI blob * across multiple SMB/SessionSetup commands. * While we should look at the uid returned in the response * to the first SessionSetup and use that as a key * instead for simplicity we assume there will not be several * such authentication at once on a single tcp session */ if( (!pinfo->fd->flags.visited) && (oidvalue) && (tvb_length(gss_tvb)==tvb_reported_length(gss_tvb)) && (len1>(guint32)tvb_length_remaining(gss_tvb, oid_start_offset)) && (gssapi_reassembly) ){ fi=se_new(gssapi_frag_info_t); fi->first_frame=pinfo->fd->num; fi->reassembled_in=0; se_tree_insert32(gss_info->frags, pinfo->fd->num, fi); fragment_add(&gssapi_reassembly_table, gss_tvb, 0, pinfo, pinfo->fd->num, NULL, 0, tvb_length(gss_tvb), TRUE); fragment_set_tot_len(&gssapi_reassembly_table, pinfo, pinfo->fd->num, NULL, len1+oid_start_offset); gss_info->do_reassembly=TRUE; gss_info->first_frame=pinfo->fd->num; gss_info->frag_offset=tvb_length(gss_tvb); goto done; } /* * Hand off to subdissector. */ if ((oidvalue == NULL) || !proto_is_protocol_enabled(oidvalue->proto)) { /* No dissector for this oid */ proto_tree_add_text(subtree, gss_tvb, oid_start_offset, -1, "Token object"); return_offset = tvb_length(gss_tvb); goto done; } /* Save a pointer to the data for the OID for the * GSSAPI protocol for this conversation. */ /* * Now add the proto data ... * but only if it is not already there. */ if(!gss_info->oid){ gss_info->oid=oidvalue; } if (is_verifier) { handle = oidvalue->wrap_handle; if (handle != NULL) { oid_tvb = tvb_new_subset_remaining(gss_tvb, offset); len = call_dissector(handle, oid_tvb, pinfo, subtree); if (len == 0) return_offset = tvb_length(gss_tvb); else return_offset = offset + len; } else { proto_tree_add_text(subtree, gss_tvb, offset, -1, "Authentication verifier"); return_offset = tvb_length(gss_tvb); } } else { handle = oidvalue->handle; if (handle != NULL) { oid_tvb = tvb_new_subset_remaining(gss_tvb, offset); len = call_dissector(handle, oid_tvb, pinfo, subtree); if (len == 0) return_offset = tvb_length(gss_tvb); else return_offset = offset + len; } else { proto_tree_add_text(subtree, gss_tvb, offset, -1, "Authentication credentials"); return_offset = tvb_length(gss_tvb); } } done: ; } CATCH_NONFATAL_ERRORS { /* * Somebody threw an exception that means that there * was a problem dissecting the payload; that means * that a dissector was found, so we don't need to * dissect the payload as data or update the protocol * or info columns. * * Just show the exception and then drive on to show * the trailer, after noting that a dissector was found * and restoring the protocol value that was in effect * before we called the subdissector. * * Restore the private_data structure in case one of the * called dissectors modified it (and, due to the exception, * was unable to restore it). */ pinfo->private_data = pd_save; show_exception(gss_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); } ENDTRY; proto_item_set_len(item, return_offset); return return_offset; }
static int dissect_headers(proto_tree *tree, tvbuff_t *tvb, int offset, packet_info *pinfo) { proto_tree *hdrs_tree = NULL; proto_tree *hdr_tree = NULL; proto_item *hdr = NULL; proto_item *handle_item; gint item_length = -1; guint8 hdr_id, i; if (tvb_length_remaining(tvb, offset) > 0) { proto_item *hdrs; hdrs = proto_tree_add_text(tree, tvb, offset, item_length, "Headers"); hdrs_tree = proto_item_add_subtree(hdrs, ett_btobex_hdrs); } else { return offset; } while (tvb_length_remaining(tvb, offset) > 0) { hdr_id = tvb_get_guint8(tvb, offset); switch(0xC0 & hdr_id) { case 0x00: /* null terminated unicode */ item_length = tvb_get_ntohs(tvb, offset+1); break; case 0x40: /* byte sequence */ item_length = tvb_get_ntohs(tvb, offset+1); break; case 0x80: /* 1 byte */ item_length = 2; break; case 0xc0: /* 4 bytes */ item_length = 5; break; } hdr = proto_tree_add_text(hdrs_tree, tvb, offset, item_length, "%s", val_to_str_ext_const(hdr_id, &header_id_vals_ext, "Unknown")); hdr_tree = proto_item_add_subtree(hdr, ett_btobex_hdr); proto_tree_add_item(hdr_tree, hf_hdr_id, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; switch(0xC0 & hdr_id) { case 0x00: /* null terminated unicode */ { proto_tree_add_item(hdr_tree, hf_hdr_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; if ((item_length - 3) > 0) { char *str; display_unicode_string(tvb, hdr_tree, offset, &str); proto_item_append_text(hdr_tree, " (\"%s\")", str); col_append_fstr(pinfo->cinfo, COL_INFO, " \"%s\"", str); } else { col_append_str(pinfo->cinfo, COL_INFO, " \"\""); } offset += item_length - 3; } break; case 0x40: /* byte sequence */ proto_tree_add_item(hdr_tree, hf_hdr_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; handle_item = proto_tree_add_item(hdr_tree, hf_hdr_val_byte_seq, tvb, offset, item_length - 3, ENC_NA); if (((hdr_id == 0x46) || (hdr_id == 0x4a)) && (item_length == 19)) { /* target or who */ for(i=0; target_vals[i].strptr != NULL; i++) { if (tvb_memeql(tvb, offset, target_vals[i].value, 16) == 0) { proto_item_append_text(handle_item, ": %s", target_vals[i].strptr); proto_item_append_text(hdr_tree, " (%s)", target_vals[i].strptr); col_append_fstr(pinfo->cinfo, COL_INFO, " - %s", target_vals[i].strptr); } } } if (!tvb_strneql(tvb, offset, "<?xml", 5)) { tvbuff_t* next_tvb = tvb_new_subset_remaining(tvb, offset); call_dissector(xml_handle, next_tvb, pinfo, tree); } else if (is_ascii_str(tvb_get_ptr(tvb, offset,item_length - 3), item_length - 3)) { proto_item_append_text(hdr_tree, " (\"%s\")", tvb_get_ephemeral_string(tvb, offset,item_length - 3)); col_append_fstr(pinfo->cinfo, COL_INFO, " \"%s\"", tvb_get_ephemeral_string(tvb, offset,item_length - 3)); } offset += item_length - 3; break; case 0x80: /* 1 byte */ proto_item_append_text(hdr_tree, " (%i)", tvb_get_ntohl(tvb, offset)); proto_tree_add_item(hdr_tree, hf_hdr_val_byte, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; break; case 0xc0: /* 4 bytes */ proto_item_append_text(hdr_tree, " (%i)", tvb_get_ntohl(tvb, offset)); proto_tree_add_item(hdr_tree, hf_hdr_val_long, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; break; default: break; } } return offset; }
static void dissect_sap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 0; int sap_version, is_ipv6, is_del, is_enc, is_comp, addr_len; guint8 vers_flags; guint8 auth_len; guint8 auth_flags; tvbuff_t *next_tvb; proto_item *si, *sif; proto_tree *sap_tree = NULL, *sap_flags_tree; col_set_str(pinfo->cinfo, COL_PROTOCOL, "SAP"); col_clear(pinfo->cinfo, COL_INFO); vers_flags = tvb_get_guint8(tvb, offset); is_ipv6 = vers_flags&MCAST_SAP_BIT_A; is_del = vers_flags&MCAST_SAP_BIT_T; is_enc = vers_flags&MCAST_SAP_BIT_E; is_comp = vers_flags&MCAST_SAP_BIT_C; sap_version = (vers_flags&MCAST_SAP_VERSION_MASK)>>MCAST_SAP_VERSION_SHIFT; addr_len = (is_ipv6) ? (int)sizeof(struct e_in6_addr) : 4; col_add_fstr(pinfo->cinfo, COL_INFO, "%s (v%u)", (is_del) ? "Deletion" : "Announcement", sap_version); if (tree) { si = proto_tree_add_item(tree, proto_sap, tvb, offset, -1, ENC_NA); sap_tree = proto_item_add_subtree(si, ett_sap); sif = proto_tree_add_item(sap_tree, hf_sap_flags, tvb, offset, 1, ENC_NA); sap_flags_tree = proto_item_add_subtree(sif, ett_sap_flags); proto_tree_add_item(sap_flags_tree, hf_sap_flags_v, tvb, offset, 1, ENC_NA); proto_tree_add_item(sap_flags_tree, hf_sap_flags_a, tvb, offset, 1, ENC_NA); proto_tree_add_item(sap_flags_tree, hf_sap_flags_r, tvb, offset, 1, ENC_NA); proto_tree_add_item(sap_flags_tree, hf_sap_flags_t, tvb, offset, 1, ENC_NA); proto_tree_add_item(sap_flags_tree, hf_sap_flags_e, tvb, offset, 1, ENC_NA); proto_tree_add_item(sap_flags_tree, hf_sap_flags_c, tvb, offset, 1, ENC_NA); } offset++; auth_len = tvb_get_guint8(tvb, offset); proto_tree_add_item(sap_tree, hf_sap_auth_len, tvb, offset, 1, ENC_NA); offset++; proto_tree_add_item(sap_tree, hf_sap_message_identifier_hash, tvb, offset, 2, ENC_BIG_ENDIAN); offset +=2; if (is_ipv6) proto_tree_add_item(sap_tree, hf_sap_originating_source_ipv6, tvb, offset, addr_len, ENC_NA); else proto_tree_add_item(sap_tree, hf_sap_originating_source_ipv4, tvb, offset, addr_len, ENC_BIG_ENDIAN); offset += addr_len; /* Authentication data lives in its own subtree */ if (auth_len > 0) { guint32 auth_data_len; proto_item *sdi, *sai; proto_tree *sa_tree, *saf_tree; int has_pad; guint8 pad_len = 0; auth_data_len = (guint32)(auth_len * sizeof(guint32)); sdi = proto_tree_add_item(sap_tree, hf_auth_data, tvb, offset, auth_data_len, ENC_NA); sa_tree = proto_item_add_subtree(sdi, ett_sap_auth); auth_flags = tvb_get_guint8(tvb, offset); sai = proto_tree_add_item(sa_tree, hf_auth_flags, tvb, offset, 1, ENC_NA); saf_tree = proto_item_add_subtree(sai, ett_sap_authf); proto_tree_add_item(saf_tree, hf_auth_flags_v, tvb, offset, 1, ENC_NA); proto_tree_add_item(saf_tree, hf_auth_flags_p, tvb, offset, 1, ENC_NA); proto_tree_add_item(saf_tree, hf_auth_flags_t, tvb, offset, 1, ENC_NA); has_pad = auth_flags&MCAST_SAP_AUTH_BIT_P; if (has_pad) { pad_len = tvb_get_guint8(tvb, offset+auth_data_len-1); } if ((int) auth_data_len - pad_len - 1 < 0) { expert_add_info_format(pinfo, sai, &ei_sap_bogus_authentication_or_pad_length, "Bogus authentication length (%d) or pad length (%d)", auth_len, pad_len); return; } proto_tree_add_item(sa_tree, hf_sap_auth_subheader, tvb, offset+1, auth_data_len-pad_len-1, ENC_NA); if (has_pad) { proto_tree_add_item(sa_tree, hf_sap_auth_data_padding_len, tvb, offset+auth_data_len-1, 1, ENC_NA); proto_tree_add_item(sa_tree, hf_sap_auth_data_padding, tvb, offset+auth_data_len-pad_len, pad_len, ENC_NA); } offset += auth_data_len; } if (is_enc || is_comp) { expert_field *mangle; if (is_enc && is_comp) mangle = &ei_sap_compressed_and_encrypted; else if (is_enc) mangle = &ei_sap_encrypted; else mangle = &ei_sap_compressed; proto_tree_add_expert(sap_tree, pinfo, mangle, tvb, offset, -1); return; } if (tree) { /* Do we have the optional payload type aka. MIME content specifier */ if (tvb_strneql(tvb, offset, "v=", strlen("v="))) { gint remaining_len; guint32 pt_len; int pt_string_len; guint8* pt_str; remaining_len = tvb_captured_length_remaining(tvb, offset); if (remaining_len == 0) { /* * "tvb_strneql()" failed because there was no * data left in the packet. * * Set the remaining length to 1, so that * we throw the appropriate exception in * "tvb_get_ptr()", rather than displaying * the payload type. */ remaining_len = 1; } pt_string_len = tvb_strnlen(tvb, offset, remaining_len); if (pt_string_len == -1) { /* * We didn't find a terminating '\0'; run to the * end of the buffer. */ pt_string_len = remaining_len; pt_len = pt_string_len; } else { /* * Include the '\0' in the total item length. */ pt_len = pt_string_len + 1; } pt_str = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, pt_string_len, ENC_ASCII); proto_tree_add_string_format_value(sap_tree, hf_sap_payload_type, tvb, offset, pt_len, pt_str, "%.*s", pt_string_len, pt_str); offset += pt_len; } } /* Done with SAP */ next_tvb = tvb_new_subset_remaining(tvb, offset); call_dissector(sdp_handle, next_tvb, pinfo, tree); }