+ offset += hdr->frag_len;
+ if (tvb_length_remaining(tvb, offset) > 0) {
+ switch (hdr->auth_proto) {
+
+ case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
+ ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
+ auth_tree = proto_item_add_subtree (ti, ett_decrpc_krb5_auth_verf);
+ protection_level = tvb_get_guint8 (tvb, offset);
+ if (auth_level_p != NULL)
+ *auth_level_p = protection_level;
+ proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
+ offset++;
+ proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
+ offset++;
+ if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
+ offset += 6; /* 6 bytes of padding */
+ else
+ offset += 2; /* 6 bytes of padding */
+ proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
+ offset += 16;
+ break;
+
+ default:
+ proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
+ break;
+ }
+ }
+}
+
+static void
+dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *dcerpc_tree,
+ e_dce_dg_common_hdr_t *hdr)
+{
+ guint32 version;
+
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ hdr->drep, hf_dcerpc_dg_cancel_vers,
+ &version);
+
+ switch (version) {
+
+ case 0:
+ /* The only version we know about */
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ hdr->drep, hf_dcerpc_dg_cancel_id,
+ NULL);
+ offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
+ hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
+ NULL);
+ break;
+ }
+}
+
+static void
+dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *dcerpc_tree,
+ e_dce_dg_common_hdr_t *hdr)
+{
+ guint32 version;
+
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ hdr->drep, hf_dcerpc_dg_cancel_vers,
+ &version);
+
+ switch (version) {
+
+ case 0:
+ /* The only version we know about */
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ hdr->drep, hf_dcerpc_dg_cancel_id,
+ NULL);
+ /* XXX - are NDR booleans 32 bits? */
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
+ NULL);
+ break;
+ }
+}
+
+static void
+dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *dcerpc_tree,
+ e_dce_dg_common_hdr_t *hdr)
+{
+ guint8 version;
+ guint16 serial_num;
+ guint16 selack_len;
+ guint i;
+
+ offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
+ hdr->drep, hf_dcerpc_dg_fack_vers,
+ &version);
+ /* padding */
+ offset++;
+
+ switch (version) {
+
+ case 0: /* The only version documented in the DCE RPC 1.1 spec */
+ case 1: /* This appears to be the same */
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
+ hdr->drep, hf_dcerpc_dg_fack_window_size,
+ NULL);
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
+ NULL);
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
+ NULL);
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
+ hdr->drep, hf_dcerpc_dg_fack_serial_num,
+ &serial_num);
+ if (check_col (pinfo->cinfo, COL_INFO)) {
+ col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
+ serial_num);
+ }
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
+ hdr->drep, hf_dcerpc_dg_fack_selack_len,
+ &selack_len);
+ for (i = 0; i < selack_len; i++) {
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ hdr->drep, hf_dcerpc_dg_fack_selack,
+ NULL);
+ }
+
+ break;
+ }
+}
+
+static void
+dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *dcerpc_tree,
+ e_dce_dg_common_hdr_t *hdr)
+{
+ guint32 status;
+
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ hdr->drep, hf_dcerpc_dg_status,
+ &status);
+
+ if (check_col (pinfo->cinfo, COL_INFO)) {
+ col_append_fstr (pinfo->cinfo, COL_INFO,
+ ": status: %s",
+ val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
+ }
+}
+
+static void
+dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *dcerpc_tree, proto_tree *tree,
+ e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
+{
+ int length, reported_length, stub_length;
+ gboolean save_fragmented;
+ fragment_data *fd_head;
+
+ if (check_col (pinfo->cinfo, COL_INFO)) {
+ col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u",
+ di->call_data->opnum);
+ }
+
+ length = tvb_length_remaining (tvb, offset);
+ reported_length = tvb_reported_length_remaining (tvb, offset);
+ stub_length = hdr->frag_len;
+ if (length > stub_length)
+ length = stub_length;
+ if (reported_length > stub_length)
+ reported_length = stub_length;
+
+ save_fragmented = pinfo->fragmented;
+
+ /* If we don't have reassembly enabled, or this packet contains
+ the entire PDU, or if this is a short frame (or a frame
+ not reassembled at a lower layer) that doesn't include all
+ the data in the fragment, just call the handoff directly if
+ this is the first fragment or the PDU isn't fragmented. */
+ if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
+ !tvb_bytes_exist(tvb, offset, stub_length) ){
+ if(hdr->frag_num == 0) {
+ /* First fragment, possibly the only fragment */
+
+ /*
+ * XXX - authentication info?
+ */
+ pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
+ dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
+ tvb_new_subset (tvb, offset, length,
+ reported_length),
+ 0, hdr->drep, di, NULL);
+ } else {
+ /* PDU is fragmented and this isn't the first fragment */
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
+ }
+ if (dcerpc_tree) {
+ if (length > 0) {
+ proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
+ "Fragment data (%d byte%s)",
+ stub_length,
+ plurality(stub_length, "", "s"));
+ }
+ }
+ }
+ } else {
+ /* Reassembly is enabled, the PDU is fragmented, and
+ we have all the data in the fragment; the first two
+ of those mean we should attempt reassembly, and the
+ third means we can attempt reassembly. */
+ if (dcerpc_tree) {
+ if (length > 0) {
+ proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
+ "Fragment data (%d byte%s)", stub_length,
+ plurality(stub_length, "", "s"));
+ }
+ }
+
+ fd_head = fragment_add_seq(tvb, offset, pinfo,
+ hdr->seqnum, dcerpc_cl_reassemble_table,
+ hdr->frag_num, stub_length,
+ !(hdr->flags1 & PFCL1_LASTFRAG));
+ if (fd_head != NULL) {
+ /* We completed reassembly */
+ tvbuff_t *next_tvb;
+
+ next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
+ tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+ add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
+ show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
+ dcerpc_tree, pinfo, next_tvb);
+
+ /*
+ * XXX - authentication info?
+ */
+ pinfo->fragmented = FALSE;
+ dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
+ 0, hdr->drep, di, NULL);
+ } else {
+ /* Reassembly isn't completed yet */
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
+ }
+ }
+ }
+ pinfo->fragmented = save_fragmented;
+}
+
+static void
+dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *dcerpc_tree, proto_tree *tree,
+ e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
+{
+ dcerpc_info di;
+ dcerpc_call_value *value, v;
+
+ if(!(pinfo->fd->flags.visited)){
+ dcerpc_call_value *call_value;
+ dcerpc_call_key *call_key;
+
+ call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
+ call_key->conv=conv;
+ call_key->call_id=hdr->seqnum;
+ call_key->smb_fid=get_smb_fid(pinfo->private_data);
+
+ call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
+ call_value->uuid = hdr->if_id;
+ call_value->ver = hdr->if_ver;
+ call_value->opnum = hdr->opnum;
+ call_value->req_frame=pinfo->fd->num;
+ call_value->req_time.secs=pinfo->fd->abs_secs;
+ call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
+ call_value->rep_frame=0;
+ call_value->max_ptr=0;
+ call_value->private_data = NULL;
+ g_hash_table_insert (dcerpc_calls, call_key, call_value);
+
+ g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
+ }
+
+ value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
+ if (!value) {
+ v.uuid = hdr->if_id;
+ v.ver = hdr->if_ver;
+ v.opnum = hdr->opnum;
+ v.req_frame = pinfo->fd->num;
+ v.rep_frame = 0;
+ v.max_ptr = 0;
+ v.private_data=NULL;
+ value = &v;
+ }
+
+ di.conv = conv;
+ di.call_id = hdr->seqnum;
+ di.smb_fid = -1;
+ di.request = TRUE;
+ di.call_data = value;
+
+ if(value->rep_frame!=0){
+ proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
+ tvb, 0, 0, value->rep_frame);
+ }
+ dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di);
+}
+
+static void
+dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *dcerpc_tree, proto_tree *tree,
+ e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
+{
+ dcerpc_info di;
+ dcerpc_call_value *value, v;
+
+ if(!(pinfo->fd->flags.visited)){
+ dcerpc_call_value *call_value;
+ dcerpc_call_key call_key;
+
+ call_key.conv=conv;
+ call_key.call_id=hdr->seqnum;
+ call_key.smb_fid=get_smb_fid(pinfo->private_data);
+
+ if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
+ g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
+ if(call_value->rep_frame==0){
+ call_value->rep_frame=pinfo->fd->num;
+ }
+ }
+ }
+
+ value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
+ if (!value) {
+ v.uuid = hdr->if_id;
+ v.ver = hdr->if_ver;
+ v.opnum = hdr->opnum;
+ v.req_frame=0;
+ v.rep_frame=pinfo->fd->num;
+ v.private_data=NULL;
+ value = &v;
+ }
+
+ di.conv = conv;
+ di.call_id = 0;
+ di.smb_fid = -1;
+ di.request = FALSE;
+ di.call_data = value;
+
+ if(value->req_frame!=0){
+ nstime_t ns;
+ proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
+ tvb, 0, 0, value->req_frame);
+ ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
+ ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
+ if(ns.nsecs<0){
+ ns.nsecs+=1000000000;
+ ns.secs--;
+ }
+ proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);