diff options
author | Tim Potter <tpot@samba.org> | 2003-09-26 06:30:13 +0000 |
---|---|---|
committer | Tim Potter <tpot@samba.org> | 2003-09-26 06:30:13 +0000 |
commit | 2d33b6281143179a7886395d4ed07470ec009c7c (patch) | |
tree | 4832de6deb2c0fde7ea8bec650726cc011cd2f95 /packet-dcerpc.c | |
parent | 6a389c8bd14c71673cf005bd9f49aff59595f340 (diff) |
This commit refactors the dcerpc authentication subdissectors for
handling encrypted request/response PDUs. Instead of having
dissection function pointers which perform both decryption and
dissection, the function pointers now only decrypt the DCERPC fragment
payload. Dissection is handled by the dcerpc_try_handoff() function
(with DCERPC fragment reassembly if necessary).
Details:
- Move the dcerpc_auth_info struct into dcerpc.h as it is now used in
the function prototype for the decryption function handlers.
- decode_encrypted_data() was refactored to take a boolean request
parameter instead of passing the DCERPC PDU packet type.
- A tvbuff_t * data field was added to dcerpc_auth to hold the
verifier. This is passed as an argument to the decryption function
handlers.
- Dissection of verifiers in request and response PDUs was moved to
before the payload.
- The dissect_dcerpc_cn_stub() function was refactored to perform
the decryption process and hand decrypted data to the reassembly
code instead of performing the decryption after reassembly.
- Removed references to decrypted_info_t as it's not necessary
anymore.
Code was tested using encrypted and unencrypted fragmented PDUs.
Before this commit ethereal could not dissect unencrypted (!)
fragmented PDUs correctly.
svn path=/trunk/; revision=8546
Diffstat (limited to 'packet-dcerpc.c')
-rw-r--r-- | packet-dcerpc.c | 230 |
1 files changed, 105 insertions, 125 deletions
diff --git a/packet-dcerpc.c b/packet-dcerpc.c index 23a32e8c62..32ac406d42 100644 --- a/packet-dcerpc.c +++ b/packet-dcerpc.c @@ -3,7 +3,7 @@ * Copyright 2001, Todd Sabin <tas@webspan.net> * Copyright 2003, Tim Potter <tpot@samba.org> * - * $Id: packet-dcerpc.c,v 1.141 2003/09/26 04:43:05 tpot Exp $ + * $Id: packet-dcerpc.c,v 1.142 2003/09/26 06:30:13 tpot Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -431,14 +431,6 @@ get_next_di(void) return &di[di_counter]; } - -typedef struct _dcerpc_auth_info { - guint8 auth_pad_len; - guint8 auth_level; - guint8 auth_type; - guint32 auth_size; -} dcerpc_auth_info; - /* try to desegment big DCE/RPC packets over TCP? */ static gboolean dcerpc_cn_desegment = TRUE; @@ -556,28 +548,23 @@ static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo, /* Hand off payload data to a registered dissector */ -static void dissect_encrypted_data(tvbuff_t *enc_tvb, packet_info *pinfo, - proto_tree *tree, - dcerpc_auth_subdissector_fns *auth_fns, - guint8 ptype, char *drep) +static tvbuff_t *decode_encrypted_data(tvbuff_t *enc_tvb, + packet_info *pinfo, + dcerpc_auth_subdissector_fns *auth_fns, + gboolean is_request, + dcerpc_auth_info *auth_info) { - dcerpc_dissect_fnct_t *fn = NULL; + dcerpc_decode_data_fnct_t *fn; - switch (ptype) { - case PDU_REQ: + if (is_request) fn = auth_fns->req_data_fn; - break; - case PDU_RESP: + else fn = auth_fns->resp_data_fn; - break; - default: - g_warning("attempt to dissect %s pdu encrypted data", - val_to_str(ptype, pckt_vals, "Unknown (%u)")); - break; - } if (fn) - fn(enc_tvb, 0, pinfo, tree, drep); + return fn(enc_tvb, 0, pinfo, auth_info); + + return NULL; } /* @@ -1812,47 +1799,13 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree, name, info->call_data->opnum); } - /* - * If the authentication level is DCE_C_AUTHN_LEVEL_PKT_PRIVACY, - * the stub data is encrypted, and we'd have to decrypt it in - * order to dissect it. - */ - if (auth_info != NULL && - auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) { - length = tvb_length_remaining (tvb, offset); - - if (length > 0) { - dcerpc_auth_subdissector_fns *auth_fns; - decrypted_info_t *dit; - tvbuff_t *enc_tvb; - - enc_tvb = tvb_new_subset(tvb, offset, length, length); - - proto_tree_add_text(sub_tree, enc_tvb, 0, length, - "Encrypted stub data (%d byte%s)", - length, plurality(length, "", "s")); - - pinfo->decrypted_data = NULL; - - if ((auth_fns = get_auth_subdissector_fns( - auth_info->auth_level, auth_info->auth_type))) - dissect_encrypted_data( - enc_tvb, pinfo, sub_tree, auth_fns, - info->request ? PDU_REQ : PDU_RESP, drep); - - /* No decrypted data so don't try and call a subdissector */ - - if (!pinfo->decrypted_data) - goto done; + sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp; - dit = (decrypted_info_t *)pinfo->decrypted_data; - tvb = dit->decr_tvb; - sub_tree = dit->decr_tree; - } - } + /* Call subdissector if we have a zero auth_level and no decrypted data, + or non-zero auth_level and sucessfully decrypted data. */ - sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp; - if (sub_dissect) { + if (sub_dissect && ((!auth_info->auth_level && !pinfo->decrypted_data) || + (auth_info->auth_level && pinfo->decrypted_data))) { saved_proto = pinfo->current_proto; saved_private_data = pinfo->private_data; pinfo->current_proto = sub_proto->name; @@ -1902,7 +1855,6 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree, } } - done: tap_queue_packet(dcerpc_tap, pinfo, info); return 0; } @@ -1914,6 +1866,8 @@ dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo, { int auth_offset; + auth_info->auth_data = NULL; + if (auth_info->auth_size != 0) { dcerpc_auth_subdissector_fns *auth_fns; tvbuff_t *auth_tvb; @@ -1923,6 +1877,8 @@ dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo, auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len, hdr->auth_len); + auth_info->auth_data = auth_tvb; + if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level, auth_info->auth_type))) dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns, @@ -1957,6 +1913,7 @@ dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr * If the full packet is here, and we've got an auth len, and it's * valid, then dissect the auth info. */ + if (tvb_length (tvb) >= hdr->frag_len && hdr->auth_len && (hdr->auth_len + 8 <= hdr->frag_len)) { @@ -2368,6 +2325,8 @@ fragment_type(guint8 flags) return "unknown"; } +/* Dissect stub data (payload) of a DCERPC packet. */ + static void dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *dcerpc_tree, proto_tree *tree, @@ -2375,29 +2334,68 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo, dcerpc_auth_info *auth_info, guint32 alloc_hint, guint32 frame) { - int length, reported_length, stub_length; - gboolean save_fragmented; + gboolean save_fragmented, payload_ok; fragment_data *fd_head=NULL; guint32 tot_len; + tvbuff_t *payload_tvb; + save_fragmented = pinfo->fragmented; - length = tvb_length_remaining(tvb, offset); - reported_length = tvb_reported_length_remaining(tvb, offset); - stub_length = hdr->frag_len - offset - auth_info->auth_size; - if (length > stub_length) - length = stub_length; - if (reported_length > stub_length) - reported_length = stub_length; + payload_tvb = tvb_new_subset( + tvb, offset, tvb_length_remaining(tvb, offset) - + auth_info->auth_size, tvb_length_remaining(tvb, offset) - + auth_info->auth_size); - save_fragmented = pinfo->fragmented; + payload_ok = TRUE; + + /* Decrypt the PDU if it is encrypted */ + + pinfo->decrypted_data = NULL; + + if (auth_info->auth_type) { + dcerpc_auth_subdissector_fns *auth_fns; + + if (dcerpc_tree) + proto_tree_add_text( + dcerpc_tree, payload_tvb, 0, -1, + "Encrypted Stub Data (%d byte%s)", + tvb_length(payload_tvb), + plurality(tvb_length(payload_tvb), "", "s")); + + if ((auth_fns = get_auth_subdissector_fns( + auth_info->auth_level, auth_info->auth_type))) { + tvbuff_t *result; + + result = decode_encrypted_data( + payload_tvb, pinfo, auth_fns, + hdr->ptype == PDU_REQ, auth_info); + + if (result) { + int len = tvb_length(result); + + add_new_data_source( + pinfo, result, "Decrypted Stub Data"); + + pinfo->decrypted_data = result; + + proto_tree_add_text( + dcerpc_tree, result, 0, len, + "Decrypted Stub Data (%d byte%s)", + len, plurality(len, "", "s")); + } else + payload_ok = FALSE; + } + } /* if this packet is not fragmented, just dissect it and exit */ if(PFC_NOT_FRAGMENTED(hdr)){ pinfo->fragmented = FALSE; - dcerpc_try_handoff (pinfo, tree, dcerpc_tree, - tvb_new_subset (tvb, offset, length, reported_length), - 0, hdr->drep, di, auth_info); + dcerpc_try_handoff( + pinfo, tree, dcerpc_tree, + pinfo->decrypted_data ? pinfo->decrypted_data : payload_tvb, + 0, hdr->drep, di, auth_info); + pinfo->fragmented = save_fragmented; return; } @@ -2409,10 +2407,12 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo, then just dissect it and exit */ if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){ - dcerpc_try_handoff (pinfo, tree, dcerpc_tree, - tvb_new_subset (tvb, offset, length, - reported_length), - 0, hdr->drep, di, auth_info); + + dcerpc_try_handoff( + pinfo, tree, dcerpc_tree, + pinfo->decrypted_data ? pinfo->decrypted_data : + payload_tvb, 0, hdr->drep, di, auth_info); + if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC %s fragment]", fragment_type(hdr->flags)); @@ -2421,56 +2421,46 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo, return; } + /* Replace encrypted payload with decrypted version for reassembly. */ + + if (pinfo->decrypted_data) + payload_tvb = (tvbuff_t *)pinfo->decrypted_data; + /* if we have already seen this packet, see if it was reassembled and if so dissect the full pdu. then exit */ if(pinfo->fd->flags.visited){ fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table); - goto end_cn_stub; } - /* if we are not doing reassembly and it was neither a complete PDU nor the first fragment then there is nothing more we can do so we just have to exit */ - if( !dcerpc_reassemble ){ + if( !dcerpc_reassemble ) goto end_cn_stub; - } /* if we didnt get 'frame' we dont know where the PDU started and thus it is pointless to continue */ - if(!frame){ + if(!frame) goto end_cn_stub; - } - /* from now on we must attempt to reassemble the PDU */ - - /* we dont have the full fragment so we just have to abort and exit - */ - if( !tvb_bytes_exist(tvb, offset, stub_length) ){ - goto end_cn_stub; - } - - /* if we get here we know it is the first time we see the packet and we also know it is only a fragment and not a full PDU, thus we must reassemble it. */ - /* if this is the first fragment we need to start reassembly */ if(hdr->flags&PFC_FIRST_FRAG){ - fragment_add(tvb, offset, pinfo, frame, - dcerpc_co_reassemble_table, - 0, stub_length, TRUE); + fragment_add(payload_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table, + 0, tvb_length(payload_tvb), TRUE); fragment_set_tot_len(pinfo, frame, dcerpc_co_reassemble_table, alloc_hint); @@ -2481,10 +2471,9 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo, if(!(hdr->flags&PFC_LAST_FRAG)){ tot_len = fragment_get_tot_len(pinfo, frame, dcerpc_co_reassemble_table); - fragment_add(tvb, offset, pinfo, frame, + fragment_add(payload_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table, - tot_len-alloc_hint, - stub_length, + tot_len-alloc_hint, tvb_length(payload_tvb), TRUE); goto end_cn_stub; @@ -2494,42 +2483,35 @@ dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo, */ tot_len = fragment_get_tot_len(pinfo, frame, dcerpc_co_reassemble_table); - fd_head = fragment_add(tvb, offset, pinfo, + fd_head = fragment_add(payload_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table, - tot_len-alloc_hint, - stub_length, + tot_len-alloc_hint, tvb_length(payload_tvb), TRUE); end_cn_stub: - /* Show the fragment data. */ - if (dcerpc_tree) { - if (length > 0) { - proto_tree_add_text (dcerpc_tree, tvb, offset, length, - "Fragment data (%d byte%s)", - stub_length, - plurality(stub_length, "", "s")); - } - } - /* if reassembly is complete, dissect the full PDU */ if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){ + if(pinfo->fd->num==fd_head->reassembled_in){ tvbuff_t *next_tvb; next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen); - tvb_set_child_real_data_tvbuff(tvb, next_tvb); + tvb_set_child_real_data_tvbuff(payload_tvb, next_tvb); add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC"); show_fragment_tree(fd_head, &dcerpc_frag_items, dcerpc_tree, pinfo, next_tvb); pinfo->fragmented = FALSE; + dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb, 0, hdr->drep, di, auth_info); + } else { - proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in, tvb, 0, 0, fd_head->reassembled_in); + proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in, payload_tvb, 0, 0, + fd_head->reassembled_in); if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC %s fragment]", fragment_type(hdr->flags)); @@ -2538,6 +2520,7 @@ end_cn_stub: } else { /* Reassembly not complete - some fragments are missing */ + if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC %s fragment]", fragment_type(hdr->flags)); @@ -2602,6 +2585,7 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo, * and we just have a security context? */ dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info); + dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info); conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); @@ -2704,9 +2688,6 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo, } else show_stub_data (tvb, offset, dcerpc_tree, &auth_info); } - - /* Decrypt the verifier, if present */ - dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info); } static void @@ -2739,9 +2720,11 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo, * and we just have a security context? */ dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info); + dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info); conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); + if (!conv) { /* no point in creating one here, really */ show_stub_data (tvb, offset, dcerpc_tree, &auth_info); @@ -2806,9 +2789,6 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo, } else show_stub_data (tvb, offset, dcerpc_tree, &auth_info); } - - /* Decrypt the verifier, if present */ - dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info); } static void |