2 * Routines for rpc dissection
3 * Copyright 1999, Uwe Girlich <Uwe.Girlich@philosys.de>
5 * $Id: packet-rpc.c,v 1.46 2001/01/03 06:55:31 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@zing.org>
9 * Copyright 1998 Gerald Combs
11 * Copied from packet-smb.c
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
41 #include "conversation.h"
42 #include "packet-rpc.h"
47 * RFC 1831, "RPC: Remote Procedure Call Protocol Specification
50 * RFC 1832, "XDR: External Data Representation Standard";
52 * RFC 2203, "RPCSEC_GSS Protocol Specification".
56 * RFC 2695, "Authentication Mechanisms for ONC RPC"
58 * although we don't currently dissec AUTH_DES or AUTH_KERB.
61 #define RPC_RM_FRAGLEN 0x7fffffffL
63 static struct true_false_string yesno = { "Yes", "No" };
66 static const value_string rpc_msg_type[] = {
68 { RPC_REPLY, "Reply" },
72 static const value_string rpc_reply_state[] = {
73 { MSG_ACCEPTED, "accepted" },
74 { MSG_DENIED, "denied" },
78 const value_string rpc_auth_flavor[] = {
79 { AUTH_NULL, "AUTH_NULL" },
80 { AUTH_UNIX, "AUTH_UNIX" },
81 { AUTH_SHORT, "AUTH_SHORT" },
82 { AUTH_DES, "AUTH_DES" },
83 { RPCSEC_GSS, "RPCSEC_GSS" },
87 static const value_string rpc_authgss_proc[] = {
88 { RPCSEC_GSS_DATA, "RPCSEC_GSS_DATA" },
89 { RPCSEC_GSS_INIT, "RPCSEC_GSS_INIT" },
90 { RPCSEC_GSS_CONTINUE_INIT, "RPCSEC_GSS_CONTINUE_INIT" },
91 { RPCSEC_GSS_DESTROY, "RPCSEC_GSS_DESTROY" },
95 static const value_string rpc_authgss_svc[] = {
96 { RPCSEC_GSS_SVC_NONE, "rpcsec_gss_svc_none" },
97 { RPCSEC_GSS_SVC_INTEGRITY, "rpcsec_gss_svc_integrity" },
98 { RPCSEC_GSS_SVC_PRIVACY, "rpcsec_gss_svc_privacy" },
102 static const value_string rpc_accept_state[] = {
103 { SUCCESS, "RPC executed successfully" },
104 { PROG_UNAVAIL, "remote hasn't exported program" },
105 { PROG_MISMATCH, "remote can't support version #" },
106 { PROC_UNAVAIL, "program can't support procedure" },
107 { GARBAGE_ARGS, "procedure can't decode params" },
111 static const value_string rpc_reject_state[] = {
112 { RPC_MISMATCH, "RPC_MISMATCH" },
113 { AUTH_ERROR, "AUTH_ERROR" },
117 static const value_string rpc_auth_state[] = {
118 { AUTH_BADCRED, "bad credential (seal broken)" },
119 { AUTH_REJECTEDCRED, "client must begin new session" },
120 { AUTH_BADVERF, "bad verifier (seal broken)" },
121 { AUTH_REJECTEDVERF, "verifier expired or replayed" },
122 { AUTH_TOOWEAK, "rejected for security reasons" },
123 { RPCSEC_GSSCREDPROB, "GSS credential problem" },
124 { RPCSEC_GSSCTXPROB, "GSS context problem" },
129 /* the protocol number */
130 static int proto_rpc = -1;
131 static int hf_rpc_lastfrag = -1;
132 static int hf_rpc_fraglen = -1;
133 static int hf_rpc_xid = -1;
134 static int hf_rpc_msgtype = -1;
135 static int hf_rpc_version = -1;
136 static int hf_rpc_version_min = -1;
137 static int hf_rpc_version_max = -1;
138 static int hf_rpc_program = -1;
139 static int hf_rpc_programversion = -1;
140 static int hf_rpc_programversion_min = -1;
141 static int hf_rpc_programversion_max = -1;
142 static int hf_rpc_procedure = -1;
143 static int hf_rpc_auth_flavor = -1;
144 static int hf_rpc_auth_length = -1;
145 static int hf_rpc_auth_machinename = -1;
146 static int hf_rpc_auth_stamp = -1;
147 static int hf_rpc_auth_uid = -1;
148 static int hf_rpc_auth_gid = -1;
149 static int hf_rpc_authgss_v = -1;
150 static int hf_rpc_authgss_proc = -1;
151 static int hf_rpc_authgss_seq = -1;
152 static int hf_rpc_authgss_svc = -1;
153 static int hf_rpc_authgss_ctx = -1;
154 static int hf_rpc_authgss_major = -1;
155 static int hf_rpc_authgss_minor = -1;
156 static int hf_rpc_authgss_window = -1;
157 static int hf_rpc_authgss_token = -1;
158 static int hf_rpc_authgss_data_length = -1;
159 static int hf_rpc_authgss_data = -1;
160 static int hf_rpc_authgss_checksum = -1;
161 static int hf_rpc_state_accept = -1;
162 static int hf_rpc_state_reply = -1;
163 static int hf_rpc_state_reject = -1;
164 static int hf_rpc_state_auth = -1;
165 static int hf_rpc_dup = -1;
166 static int hf_rpc_call_dup = -1;
167 static int hf_rpc_reply_dup = -1;
168 static int hf_rpc_value_follows = -1;
170 static gint ett_rpc = -1;
171 static gint ett_rpc_string = -1;
172 static gint ett_rpc_cred = -1;
173 static gint ett_rpc_verf = -1;
174 static gint ett_rpc_gids = -1;
175 static gint ett_rpc_gss_data = -1;
177 /* Hash table with info on RPC program numbers */
178 static GHashTable *rpc_progs;
180 /* Hash table with info on RPC procedure numbers */
181 static GHashTable *rpc_procs;
184 /***********************************/
185 /* Hash array with procedure names */
186 /***********************************/
190 rpc_proc_equal(gconstpointer k1, gconstpointer k2)
192 rpc_proc_info_key* key1 = (rpc_proc_info_key*) k1;
193 rpc_proc_info_key* key2 = (rpc_proc_info_key*) k2;
195 return ((key1->prog == key2->prog &&
196 key1->vers == key2->vers &&
197 key1->proc == key2->proc) ?
201 /* calculate a hash key */
203 rpc_proc_hash(gconstpointer k)
205 rpc_proc_info_key* key = (rpc_proc_info_key*) k;
207 return (key->prog ^ (key->vers<<16) ^ (key->proc<<24));
211 /* insert some entries */
213 rpc_init_proc_table(guint prog, guint vers, const vsff *proc_table)
217 for (proc = proc_table ; proc->strptr!=NULL; proc++) {
218 rpc_proc_info_key *key;
219 rpc_proc_info_value *value;
221 key = (rpc_proc_info_key *) g_malloc(sizeof(rpc_proc_info_key));
224 key->proc = proc->value;
226 value = (rpc_proc_info_value *) g_malloc(sizeof(rpc_proc_info_value));
227 value->name = proc->strptr;
228 value->dissect_call = proc->dissect_call;
229 value->dissect_reply = proc->dissect_reply;
231 g_hash_table_insert(rpc_procs,key,value);
235 /*----------------------------------------*/
236 /* end of Hash array with procedure names */
237 /*----------------------------------------*/
240 /*********************************/
241 /* Hash array with program names */
242 /*********************************/
246 rpc_prog_equal(gconstpointer k1, gconstpointer k2)
248 rpc_prog_info_key* key1 = (rpc_prog_info_key*) k1;
249 rpc_prog_info_key* key2 = (rpc_prog_info_key*) k2;
251 return ((key1->prog == key2->prog) ?
256 /* calculate a hash key */
258 rpc_prog_hash(gconstpointer k)
260 rpc_prog_info_key* key = (rpc_prog_info_key*) k;
267 rpc_init_prog(int proto, guint32 prog, int ett)
269 rpc_prog_info_key *key;
270 rpc_prog_info_value *value;
272 key = (rpc_prog_info_key *) g_malloc(sizeof(rpc_prog_info_key));
275 value = (rpc_prog_info_value *) g_malloc(sizeof(rpc_prog_info_value));
276 value->proto = proto;
278 value->progname = proto_get_protocol_short_name(proto);
280 g_hash_table_insert(rpc_progs,key,value);
283 /* return the name associated with a previously registered program. This
284 should probably eventually be expanded to use the rpc YP/NIS map
285 so that it can give names for programs not handled by ethereal */
286 char *rpc_prog_name(guint32 prog)
288 char *progname = NULL;
289 rpc_prog_info_key rpc_prog_key;
290 rpc_prog_info_value *rpc_prog;
292 rpc_prog_key.prog = prog;
293 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
294 progname = "Unknown";
297 progname = rpc_prog->progname;
303 /*--------------------------------------*/
304 /* end of Hash array with program names */
305 /*--------------------------------------*/
307 /* static array, first quick implementation, I'll switch over to GList soon */
308 typedef struct _rpc_call_info {
310 conversation_t *conversation;
311 guint32 req_num; /* frame number of first request seen */
312 guint32 rep_num; /* frame number of first reply seen */
319 rpc_proc_info_value* proc_info;
322 #define RPC_CALL_TABLE_LENGTH 1000
324 rpc_call_info rpc_call_table[RPC_CALL_TABLE_LENGTH];
325 guint32 rpc_call_index = 0;
326 guint32 rpc_call_firstfree = 0;
329 rpc_call_insert(rpc_call_info *call)
331 /* some space left? */
332 if (rpc_call_firstfree<RPC_CALL_TABLE_LENGTH) {
333 /* some space left */
334 /* take the first free entry */
335 rpc_call_index = rpc_call_firstfree;
336 /* increase this limit */
337 rpc_call_firstfree++;
338 /* rpc_call_firstfree may now be RPC_CALL_TABLE_LENGTH */
342 /* the next entry, with wrap around */
343 rpc_call_index = (rpc_call_index+1) % rpc_call_firstfree;
346 /* put the entry in */
347 memcpy(&rpc_call_table[rpc_call_index],call,sizeof(*call));
352 static rpc_call_info*
353 rpc_call_lookup(rpc_call_info *call)
360 rpc_call_table[i].xid == call->xid &&
361 rpc_call_table[i].conversation == call->conversation
363 return &rpc_call_table[i];
365 if (rpc_call_firstfree) {
366 /* decrement by one, go to rpc_call_firstfree-1
367 at the start of the list */
368 i = (i-1+rpc_call_firstfree) % rpc_call_firstfree;
370 } while (i!=rpc_call_index);
376 rpc_roundup(unsigned int a)
378 unsigned int mod = a % 4;
379 return a + ((mod)? 4-mod : 0);
384 dissect_rpc_bool(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
389 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
390 value = EXTRACT_UINT(pd, offset+0);
392 proto_tree_add_boolean(tree, hfindex, NullTVB, offset, 4, value);
400 dissect_rpc_bool_tvb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
401 int hfindex, int offset)
404 proto_tree_add_item(tree, hfindex, tvb, offset, 4, FALSE);
410 dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
415 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
416 value = EXTRACT_UINT(pd, offset+0);
419 proto_tree_add_text(tree, NullTVB, offset, 4,
420 "%s: %u", name, value);
429 dissect_rpc_uint32_tvb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
430 int hfindex, int offset)
433 proto_tree_add_item(tree, hfindex, tvb, offset, 4, FALSE);
439 dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
445 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
446 value_high = EXTRACT_UINT(pd, offset+0);
447 value_low = EXTRACT_UINT(pd, offset+4);
451 proto_tree_add_text(tree, NullTVB, offset, 8,
452 "%s: 0x%x%08x", name, value_high, value_low);
454 proto_tree_add_text(tree, NullTVB, offset, 8,
455 "%s: %u", name, value_low);
464 dissect_rpc_uint64_tvb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
465 int hfindex, int offset)
470 value_high = tvb_get_ntohl(tvb, offset + 0);
471 value_low = tvb_get_ntohl(tvb, offset + 4);
475 proto_tree_add_text(tree, tvb, offset, 8,
476 "%s: 0x%x%08x", proto_registrar_get_name(hfindex), value_high, value_low);
478 proto_tree_add_uint(tree, hfindex, tvb, offset, 8, value_low);
486 dissect_rpc_opaque_data(const u_char *pd, int offset, frame_data *fd,
487 proto_tree *tree, int hfindex, gboolean string_data,
488 char **string_buffer_ret)
490 proto_item *string_item = NULL;
491 proto_tree *string_tree = NULL;
492 int old_offset = offset;
494 int length_truncated = 0;
496 int string_truncated = 0;
497 guint32 string_length = 0;
498 guint32 string_length_full;
499 guint32 string_length_packet;
500 guint32 string_length_copy = 0;
502 int fill_truncated = 0;
503 guint32 fill_length = 0;
504 guint32 fill_length_packet = 0;
505 guint32 fill_length_copy = 0;
507 char *string_buffer = NULL;
508 char *string_buffer_print = NULL;
510 if (BYTES_ARE_IN_FRAME(offset,4)) {
511 string_length = EXTRACT_UINT(pd,offset+0);
512 string_length_full = rpc_roundup(string_length);
513 string_length_packet = pi.captured_len - (offset + 4);
514 if (string_length_packet < string_length) {
515 /* truncated string */
516 string_truncated = 1;
517 string_length_copy = string_length_packet;
520 fill_length_packet = 0;
521 fill_length_copy = 0;
524 /* full string data */
525 string_truncated = 0;
526 string_length_copy = string_length;
527 fill_length = string_length_full - string_length;
528 fill_length_packet = pi.captured_len - (offset + 4 + string_length);
529 if (fill_length_packet < fill_length) {
530 /* truncated fill bytes */
531 fill_length_copy = fill_length_packet;
535 /* full fill bytes */
536 fill_length_copy = fill_length;
540 string_buffer = (char*)g_malloc(string_length_copy +
541 (string_data ? 1 : 0));
542 memcpy(string_buffer,pd+offset+4,string_length_copy);
544 string_buffer[string_length_copy] = '\0';
546 /* calculate a nice printable string */
548 if (string_length != string_length_copy) {
550 /* alloc maximum data area */
551 string_buffer_print = (char*)g_malloc(string_length_copy + 12 + 1);
552 /* copy over the data */
553 memcpy(string_buffer_print,string_buffer,string_length_copy);
554 /* append a 0 byte for sure printing */
555 string_buffer_print[string_length_copy] = '\0';
556 /* append <TRUNCATED> */
557 /* This way, we get the TRUNCATED even
558 in the case of totally wrong packets,
559 where \0 are inside the string.
560 TRUNCATED will appear at the
561 first \0 or at the end (where we
562 put the securing \0).
564 strcat(string_buffer_print,"<TRUNCATED>");
567 string_buffer_print = g_strdup("<DATA><TRUNCATED>");
572 string_buffer_print = g_strdup(string_buffer);
575 string_buffer_print = g_strdup("<DATA>");
580 string_buffer_print = g_strdup("<EMPTY>");
584 length_truncated = 1;
585 string_truncated = 2;
587 string_buffer = g_strdup("");
588 string_buffer_print = g_strdup("<TRUNCATED>");
592 string_item = proto_tree_add_text(tree, NullTVB,offset+0, END_OF_FRAME,
593 "%s: %s", proto_registrar_get_name(hfindex), string_buffer_print);
595 proto_tree_add_string_hidden(tree, hfindex, NullTVB, offset+4,
596 string_length_copy, string_buffer);
599 string_tree = proto_item_add_subtree(string_item, ett_rpc_string);
602 if (length_truncated) {
604 proto_tree_add_text(string_tree, NullTVB,
605 offset,pi.captured_len-offset,
606 "length: <TRUNCATED>");
607 offset = pi.captured_len;
610 proto_tree_add_text(string_tree, NullTVB,offset+0,4,
611 "length: %u", string_length);
615 proto_tree_add_text(string_tree, NullTVB,offset,string_length_copy,
616 "contents: %s", string_buffer_print);
617 offset += string_length_copy;
620 if (fill_truncated) {
621 proto_tree_add_text(string_tree, NullTVB,
622 offset,fill_length_copy,
623 "fill bytes: opaque data<TRUNCATED>");
626 proto_tree_add_text(string_tree, NullTVB,
627 offset,fill_length_copy,
628 "fill bytes: opaque data");
631 offset += fill_length_copy;
636 proto_item_set_len(string_item, offset - old_offset);
639 if (string_buffer != NULL) g_free (string_buffer );
640 if (string_buffer_print != NULL) {
641 if (string_buffer_ret != NULL)
642 *string_buffer_ret = string_buffer_print;
644 g_free (string_buffer_print);
651 dissect_rpc_string(const u_char *pd, int offset, frame_data *fd,
652 proto_tree *tree, int hfindex, char **string_buffer_ret)
654 offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, TRUE,
662 dissect_rpc_string_tvb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int hfindex, int offset, char **string_buffer_ret)
666 int compat_offset_new;
668 tvb_compat(tvb, &pd, &compat_offset);
669 compat_offset += offset;
671 compat_offset_new = dissect_rpc_string(pd, compat_offset, pinfo->fd,
672 tree, hfindex, string_buffer_ret);
673 offset += (compat_offset_new - compat_offset);
679 dissect_rpc_data(const u_char *pd, int offset, frame_data *fd,
680 proto_tree *tree, int hfindex)
682 offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, FALSE,
690 dissect_rpc_data_tvb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int hfindex, int offset)
694 int compat_offset_new;
696 tvb_compat(tvb, &pd, &compat_offset);
697 compat_offset += offset;
699 compat_offset_new = dissect_rpc_data(pd, compat_offset, pinfo->fd,
701 offset += (compat_offset_new - compat_offset);
707 dissect_rpc_list(const u_char *pd, int offset, frame_data *fd,
708 proto_tree *tree, dissect_function_t *rpc_list_dissector)
710 guint32 value_follows;
713 if (!BYTES_ARE_IN_FRAME(offset,4)) break;
714 value_follows = EXTRACT_UINT(pd, offset+0);
715 proto_tree_add_boolean(tree,hf_rpc_value_follows, NullTVB,
716 offset+0, 4, value_follows);
718 if (value_follows == 1) {
719 offset = rpc_list_dissector(pd, offset, fd, tree);
730 dissect_rpc_authunix_cred(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, int offset)
739 proto_tree *gtree = NULL;
741 if (!tvb_bytes_exist(tvb,offset,4)) return offset;
742 stamp = tvb_get_ntohl(tvb,offset+0);
744 proto_tree_add_uint(tree, hf_rpc_auth_stamp, tvb,
748 offset = dissect_rpc_string_tvb(tvb, pinfo, tree,
749 hf_rpc_auth_machinename, offset, NULL);
751 if (!tvb_bytes_exist(tvb,offset,4)) return offset;
752 uid = tvb_get_ntohl(tvb,offset+0);
754 proto_tree_add_uint(tree, hf_rpc_auth_uid, tvb,
758 if (!tvb_bytes_exist(tvb,offset,4)) return offset;
759 gid = tvb_get_ntohl(tvb,offset+0);
761 proto_tree_add_uint(tree, hf_rpc_auth_gid, tvb,
765 if (!tvb_bytes_exist(tvb,offset,4)) return offset;
766 gids_count = tvb_get_ntohl(tvb,offset+0);
768 gitem = proto_tree_add_text(tree, tvb,
769 offset, 4+gids_count*4, "Auxiliary GIDs");
770 gtree = proto_item_add_subtree(gitem, ett_rpc_gids);
774 if (!tvb_bytes_exist(tvb,offset,4*gids_count)) return offset;
775 for (gids_i = 0 ; gids_i < gids_count ; gids_i++) {
776 gids_entry = tvb_get_ntohl(tvb,offset+0);
778 proto_tree_add_uint(gtree, hf_rpc_auth_gid, tvb,
779 offset, 4, gids_entry);
782 /* how can I NOW change the gitem to print a list with
783 the first 16 gids? */
789 dissect_rpc_authgss_cred(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, int offset)
796 if (!tvb_bytes_exist(tvb,offset,4)) return offset;
797 agc_v = tvb_get_ntohl(tvb, offset+0);
799 proto_tree_add_uint(tree, hf_rpc_authgss_v,
800 tvb, offset+0, 4, agc_v);
803 if (!tvb_bytes_exist(tvb,offset,4)) return offset;
804 agc_proc = tvb_get_ntohl(tvb, offset+0);
806 proto_tree_add_uint(tree, hf_rpc_authgss_proc,
807 tvb, offset+0, 4, agc_proc);
810 if (!tvb_bytes_exist(tvb,offset,4)) return offset;
811 agc_seq = tvb_get_ntohl(tvb, offset+0);
813 proto_tree_add_uint(tree, hf_rpc_authgss_seq,
814 tvb, offset+0, 4, agc_seq);
817 if (!tvb_bytes_exist(tvb,offset,4)) return offset;
818 agc_svc = tvb_get_ntohl(tvb, offset+0);
820 proto_tree_add_uint(tree, hf_rpc_authgss_svc,
821 tvb, offset+0, 4, agc_svc);
824 offset = dissect_rpc_data_tvb(tvb, pinfo, tree, hf_rpc_authgss_ctx,
831 dissect_rpc_cred(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, int offset)
839 if (!tvb_bytes_exist(tvb, offset,8)) return offset;
840 flavor = tvb_get_ntohl(tvb,offset+0);
841 length = tvb_get_ntohl(tvb,offset+4);
842 length = rpc_roundup(length);
843 if (!tvb_bytes_exist(tvb,offset+8,length)) return offset;
846 citem = proto_tree_add_text(tree, tvb, offset,
847 8+length, "Credentials");
848 ctree = proto_item_add_subtree(citem, ett_rpc_cred);
849 proto_tree_add_uint(ctree, hf_rpc_auth_flavor, tvb,
850 offset+0, 4, flavor);
851 proto_tree_add_uint(ctree, hf_rpc_auth_length, tvb,
852 offset+4, 4, length);
856 dissect_rpc_authunix_cred(tvb, pinfo, ctree, offset+8);
863 /* I have no tcpdump file with such a packet to verify the
864 info from the RFC 1050 */
871 dissect_rpc_authgss_cred(tvb, pinfo, ctree, offset+8);
875 proto_tree_add_text(ctree, tvb, offset+8,
876 length,"opaque data");
880 offset += 8 + length;
886 dissect_rpc_verf(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, int offset)
894 if (!tvb_bytes_exist(tvb,offset,8)) return offset;
895 flavor = tvb_get_ntohl(tvb,offset+0);
896 length = tvb_get_ntohl(tvb,offset+4);
897 length = rpc_roundup(length);
898 if (!tvb_bytes_exist(tvb,offset+8,length)) return offset;
901 vitem = proto_tree_add_text(tree, tvb, offset,
902 8+length, "Verifier");
903 vtree = proto_item_add_subtree(vitem, ett_rpc_verf);
904 proto_tree_add_uint(vtree, hf_rpc_auth_flavor, tvb,
905 offset+0, 4, flavor);
909 proto_tree_add_uint(vtree, hf_rpc_auth_length, tvb,
910 offset+4, 4, length);
911 dissect_rpc_authunix_cred(tvb, pinfo, vtree, offset+8);
914 dissect_rpc_data_tvb(tvb, pinfo, vtree,
915 hf_rpc_authgss_checksum, offset+4);
918 proto_tree_add_uint(vtree, hf_rpc_auth_length, tvb,
919 offset+4, 4, length);
921 proto_tree_add_text(vtree, tvb, offset+8,
922 length, "opaque data");
926 offset += 8 + length;
932 dissect_rpc_authgss_initarg(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, int offset)
934 offset = dissect_rpc_data_tvb(tvb, pinfo, tree, hf_rpc_authgss_token,
940 dissect_rpc_authgss_initres(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, int offset)
942 int major, minor, window;
944 offset = dissect_rpc_data_tvb(tvb, pinfo, tree, hf_rpc_authgss_ctx,
947 if (!tvb_bytes_exist(tvb,offset,4)) return offset;
948 major = tvb_get_ntohl(tvb,offset+0);
950 proto_tree_add_uint(tree, hf_rpc_authgss_major, tvb,
954 if (!tvb_bytes_exist(tvb,offset,4)) return offset;
955 minor = tvb_get_ntohl(tvb,offset+0);
957 proto_tree_add_uint(tree, hf_rpc_authgss_minor, tvb,
961 if (!tvb_bytes_exist(tvb,offset,4)) return offset;
962 window = tvb_get_ntohl(tvb,offset+0);
964 proto_tree_add_uint(tree, hf_rpc_authgss_window, tvb,
965 offset+0, 4, window);
968 offset = dissect_rpc_data_tvb(tvb, pinfo, tree, hf_rpc_authgss_token,
976 call_dissect_function(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, dissect_function_t* dissect_function)
978 if (dissect_function != NULL) {
980 const guint8 *next_pd;
984 /* make a new tvbuff subset */
985 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
987 /* make a new pd,offset pair */
988 tvb_compat(next_tvb, &next_pd, &next_offset);
990 /* with this difference we can switch to/from old offsets */
991 offset_diff = next_offset - offset;
993 /* call the dissector for the next level */
994 next_offset = dissect_function(next_pd, next_offset,
997 /* correct the tvb offset */
998 offset = next_offset - offset_diff;
1006 dissect_rpc_authgss_integ_data(tvbuff_t *tvb, packet_info *pinfo,
1007 proto_tree *tree, int offset, dissect_function_t* dissect_function)
1009 guint32 length, seq;
1014 if (!tvb_bytes_exist(tvb, offset, 8)) return offset;
1015 length = tvb_get_ntohl(tvb, offset+0);
1016 length = rpc_roundup(length);
1017 seq = tvb_get_ntohl(tvb, offset+4);
1020 gitem = proto_tree_add_text(tree, tvb, offset,
1021 4+length, "GSS Data");
1022 gtree = proto_item_add_subtree(gitem, ett_rpc_gss_data);
1023 proto_tree_add_uint(gtree, hf_rpc_authgss_data_length,
1024 tvb, offset+0, 4, length);
1025 proto_tree_add_uint(gtree, hf_rpc_authgss_seq,
1026 tvb, offset+4, 4, seq);
1027 if (dissect_function != NULL)
1029 call_dissect_function(tvb, pinfo, gtree,
1030 offset, dissect_function);
1032 offset += 8 + length;
1033 offset = dissect_rpc_data_tvb(tvb, pinfo, tree, hf_rpc_authgss_checksum,
1040 dissect_rpc_authgss_priv_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
1042 offset = dissect_rpc_data_tvb(tvb, pinfo, tree, hf_rpc_authgss_data,
1049 dissect_rpc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1053 rpc_call_info rpc_key;
1054 rpc_call_info *rpc_call = NULL;
1055 rpc_prog_info_value *rpc_prog = NULL;
1056 rpc_prog_info_key rpc_prog_key;
1059 unsigned int rpcvers;
1060 unsigned int prog = 0;
1061 unsigned int vers = 0;
1062 unsigned int proc = 0;
1063 unsigned int flavor = 0;
1064 unsigned int gss_proc = 0;
1065 unsigned int gss_svc = 0;
1069 unsigned int reply_state;
1070 unsigned int accept_state;
1071 unsigned int reject_state;
1073 char *msg_type_name = NULL;
1075 char *procname = NULL;
1076 static char procname_static[20];
1078 unsigned int vers_low;
1079 unsigned int vers_high;
1081 unsigned int auth_state;
1083 proto_item *rpc_item=NULL;
1084 proto_tree *rpc_tree = NULL;
1086 proto_item *pitem=NULL;
1087 proto_tree *ptree = NULL;
1088 int offset_old = offset;
1093 rpc_call_info rpc_call_msg;
1094 rpc_proc_info_key key;
1095 rpc_proc_info_value *value = NULL;
1096 conversation_t* conversation;
1097 static address null_address = { AT_NONE, 0, NULL };
1099 dissect_function_t *dissect_function = NULL;
1101 if (!proto_is_protocol_enabled(proto_rpc))
1104 pinfo->current_proto = "RPC";
1106 /* TCP uses record marking */
1107 use_rm = (pinfo->ptype == PT_TCP);
1109 /* the first 4 bytes are special in "record marking mode" */
1111 if (!tvb_bytes_exist(tvb, offset, 4))
1113 rpc_rm = tvb_get_ntohl(tvb, offset);
1118 * Check to see whether this looks like an RPC call or reply.
1120 if (!tvb_bytes_exist(tvb, offset, 8)) {
1121 /* Captured data in packet isn't enough to let us tell. */
1125 /* both directions need at least this */
1126 msg_type = tvb_get_ntohl(tvb, offset + 4);
1131 /* check for RPC call */
1132 if (!tvb_bytes_exist(tvb, offset, 16)) {
1133 /* Captured data in packet isn't enough to let us
1138 /* XID can be anything, we don't check it.
1139 We already have the message type.
1140 Check whether an RPC version number of 2 is in the
1141 location where it would be, and that an RPC program
1142 number we know about is in the locaton where it would be. */
1143 rpc_prog_key.prog = tvb_get_ntohl(tvb, offset + 12);
1144 if (tvb_get_ntohl(tvb, offset + 8) != 2 ||
1145 ((rpc_prog = g_hash_table_lookup(rpc_progs, &rpc_prog_key))
1147 /* They're not, so it's probably not an RPC call. */
1153 /* Check for RPC reply. A reply must match a call that
1154 we've seen, and the reply must be sent to the same
1155 port and address that the call came from, and must
1156 come from the port to which the call was sent. (We
1157 don't worry about the address to which the call was
1158 sent and from which the reply was sent, because there's
1159 no guarantee that the reply will come from the address
1160 to which the call was sent.) */
1161 conversation = find_conversation(&null_address, &pinfo->dst,
1162 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
1163 if (conversation == NULL) {
1164 /* We haven't seen an RPC call for that conversation,
1165 so we can't check for a reply to that call. */
1169 /* The XIDs of the call and reply must match. */
1170 rpc_key.xid = tvb_get_ntohl(tvb, offset + 0);
1171 rpc_key.conversation = conversation;
1172 if ((rpc_call = rpc_call_lookup(&rpc_key)) == NULL) {
1173 /* The XID doesn't match a call from that
1174 conversation, so it's probably not an RPC reply. */
1180 /* The putative message type field contains neither
1181 RPC_CALL nor RPC_REPLY, so it's not an RPC call or
1186 if (check_col(pinfo->fd, COL_PROTOCOL))
1187 col_set_str(pinfo->fd, COL_PROTOCOL, "RPC");
1190 rpc_item = proto_tree_add_item(tree, proto_rpc, tvb, 0,
1191 tvb_length(tvb), FALSE);
1193 rpc_tree = proto_item_add_subtree(rpc_item, ett_rpc);
1197 if (use_rm && rpc_tree) {
1198 proto_tree_add_boolean(rpc_tree,hf_rpc_lastfrag, tvb,
1199 offset-4, 4, (rpc_rm >> 31) & 0x1);
1200 proto_tree_add_uint(rpc_tree,hf_rpc_fraglen, tvb,
1201 offset-4, 4, rpc_rm & RPC_RM_FRAGLEN);
1204 xid = tvb_get_ntohl(tvb, offset + 0);
1206 proto_tree_add_uint_format(rpc_tree,hf_rpc_xid, tvb,
1207 offset+0, 4, xid, "XID: 0x%x (%u)", xid, xid);
1210 msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u");
1212 proto_tree_add_uint(rpc_tree, hf_rpc_msgtype, tvb,
1213 offset+4, 4, msg_type);
1218 if (msg_type==RPC_CALL) {
1219 /* we know already the proto-entry, the ETT-const,
1221 proto = rpc_prog->proto;
1222 ett = rpc_prog->ett;
1223 progname = rpc_prog->progname;
1225 rpcvers = tvb_get_ntohl(tvb, offset + 0);
1227 proto_tree_add_uint(rpc_tree,
1228 hf_rpc_version, tvb, offset+0, 4, rpcvers);
1231 prog = tvb_get_ntohl(tvb, offset + 4);
1234 proto_tree_add_uint_format(rpc_tree,
1235 hf_rpc_program, tvb, offset+4, 4, prog,
1236 "Program: %s (%u)", progname, prog);
1239 if (check_col(pinfo->fd, COL_PROTOCOL)) {
1240 /* Set the protocol name to the underlying
1242 col_add_fstr(pinfo->fd, COL_PROTOCOL, "%s", progname);
1245 if (!tvb_bytes_exist(tvb, offset+8,4))
1247 vers = tvb_get_ntohl(tvb, offset+8);
1249 proto_tree_add_uint(rpc_tree,
1250 hf_rpc_programversion, tvb, offset+8, 4, vers);
1253 if (!tvb_bytes_exist(tvb, offset+12,4))
1255 proc = tvb_get_ntohl(tvb, offset+12);
1257 /* Check for RPCSEC_GSS */
1258 if (proc == 0 && tvb_bytes_exist(tvb, offset+16,28)) {
1259 flavor = tvb_get_ntohl(tvb, offset+16);
1260 if (flavor == RPCSEC_GSS) {
1261 gss_proc = tvb_get_ntohl(tvb, offset+28);
1262 gss_svc = tvb_get_ntohl(tvb, offset+34);
1269 if ((value = g_hash_table_lookup(rpc_procs,&key)) != NULL) {
1270 dissect_function = value->dissect_call;
1271 procname = value->name;
1274 /* happens only with strange program versions or
1275 non-existing dissectors */
1276 dissect_function = NULL;
1277 sprintf(procname_static, "proc-%u", proc);
1278 procname = procname_static;
1282 proto_tree_add_uint_format(rpc_tree,
1283 hf_rpc_procedure, tvb, offset+12, 4, proc,
1284 "Procedure: %s (%u)", procname, proc);
1287 if (check_col(pinfo->fd, COL_INFO)) {
1288 col_add_fstr(pinfo->fd, COL_INFO,"V%u %s %s XID 0x%x",
1295 /* Keep track of the address and port whence the call came,
1296 and the port to which the call is being sent, so that
1297 we can match up calls wityh replies. (We don't worry
1298 about the address to which the call was sent and from
1299 which the reply was sent, because there's no
1300 guarantee that the reply will come from the address
1301 to which the call was sent.) */
1302 conversation = find_conversation(&pinfo->src, &null_address,
1303 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
1304 if (conversation == NULL) {
1305 /* It's not part of any conversation - create a new
1307 conversation = conversation_new(&pinfo->src,
1308 &null_address, pinfo->ptype, pinfo->srcport,
1309 pinfo->destport, NULL, 0);
1312 /* prepare the key data */
1313 rpc_call_msg.xid = xid;
1314 rpc_call_msg.conversation = conversation;
1316 /* look up the request */
1317 if ((rpc_call = rpc_call_lookup(&rpc_call_msg)) != NULL) {
1318 /* We've seen a request with this XID, with the same
1319 source and destination, before - but was it
1321 if (pinfo->fd->num != rpc_call->req_num) {
1322 /* No, so it's a duplicate request.
1324 if (check_col(pinfo->fd, COL_INFO)) {
1325 col_append_fstr(pinfo->fd, COL_INFO,
1326 " dup XID 0x%x", xid);
1328 proto_tree_add_uint_hidden(rpc_tree,
1329 hf_rpc_dup, tvb, 0,0, xid);
1330 proto_tree_add_uint_hidden(rpc_tree,
1331 hf_rpc_call_dup, tvb, 0,0, xid);
1337 /* Prepare the value data.
1338 "req_num" and "rep_num" are frame numbers;
1339 frame numbers are 1-origin, so we use 0
1340 to mean "we don't yet know in which frame
1341 the reply for this call appears". */
1342 rpc_call_msg.req_num = pinfo->fd->num;
1343 rpc_call_msg.rep_num = 0;
1344 rpc_call_msg.prog = prog;
1345 rpc_call_msg.vers = vers;
1346 rpc_call_msg.proc = proc;
1347 rpc_call_msg.flavor = flavor;
1348 rpc_call_msg.gss_proc = gss_proc;
1349 rpc_call_msg.gss_svc = gss_svc;
1350 rpc_call_msg.proc_info = value;
1352 rpc_call_insert(&rpc_call_msg);
1357 offset = dissect_rpc_cred(tvb, pinfo, rpc_tree, offset);
1358 offset = dissect_rpc_verf(tvb, pinfo, rpc_tree, offset);
1360 /* go to the next dissector */
1362 } /* end of RPC call */
1363 else if (msg_type == RPC_REPLY)
1365 /* we know already the type from the calling routine,
1366 and we already have "rpc_call" set above. */
1367 prog = rpc_call->prog;
1368 vers = rpc_call->vers;
1369 proc = rpc_call->proc;
1370 flavor = rpc_call->flavor;
1371 gss_proc = rpc_call->gss_proc;
1372 gss_svc = rpc_call->gss_svc;
1374 /* Indicate the frame to which this is a reply. */
1375 proto_tree_add_text(rpc_tree, tvb, 0, 0,
1376 "This is a reply to a request starting in frame %u",
1379 if (rpc_call->proc_info != NULL) {
1380 dissect_function = rpc_call->proc_info->dissect_reply;
1381 if (rpc_call->proc_info->name != NULL) {
1382 procname = rpc_call->proc_info->name;
1385 sprintf(procname_static, "proc-%u", proc);
1386 procname = procname_static;
1390 dissect_function = NULL;
1391 sprintf(procname_static, "proc-%u", proc);
1392 procname = procname_static;
1395 rpc_prog_key.prog = prog;
1396 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
1399 progname = "Unknown";
1402 proto = rpc_prog->proto;
1403 ett = rpc_prog->ett;
1404 progname = rpc_prog->progname;
1406 if (check_col(pinfo->fd, COL_PROTOCOL)) {
1407 /* Set the protocol name to the underlying
1409 col_add_fstr(pinfo->fd, COL_PROTOCOL, "%s",
1414 if (check_col(pinfo->fd, COL_INFO)) {
1415 col_add_fstr(pinfo->fd, COL_INFO,"V%u %s %s XID 0x%x",
1423 proto_tree_add_uint_format(rpc_tree,
1424 hf_rpc_program, tvb, 0, 0, prog,
1425 "Program: %s (%u)", progname, prog);
1426 proto_tree_add_uint(rpc_tree,
1427 hf_rpc_programversion, tvb, 0, 0, vers);
1428 proto_tree_add_uint_format(rpc_tree,
1429 hf_rpc_procedure, tvb, 0, 0, proc,
1430 "Procedure: %s (%u)", procname, proc);
1433 if (rpc_call->rep_num == 0) {
1434 /* We have not yet seen a reply to that call, so
1435 this must be the first reply; remember its
1437 rpc_call->rep_num = pinfo->fd->num;
1439 /* We have seen a reply to this call - but was it
1441 if (rpc_call->rep_num != pinfo->fd->num) {
1442 /* No, so it's a duplicate reply.
1444 if (check_col(pinfo->fd, COL_INFO)) {
1445 col_append_fstr(pinfo->fd, COL_INFO,
1446 " dup XID 0x%x", xid);
1448 proto_tree_add_uint_hidden(rpc_tree,
1449 hf_rpc_dup, tvb, 0,0, xid);
1450 proto_tree_add_uint_hidden(rpc_tree,
1451 hf_rpc_reply_dup, tvb, 0,0, xid);
1457 if (!tvb_bytes_exist(tvb, offset,4))
1459 reply_state = tvb_get_ntohl(tvb,offset+0);
1461 proto_tree_add_uint(rpc_tree, hf_rpc_state_reply, tvb,
1462 offset+0, 4, reply_state);
1466 if (reply_state == MSG_ACCEPTED) {
1467 offset = dissect_rpc_verf(tvb, pinfo, rpc_tree, offset);
1468 if (!tvb_bytes_exist(tvb, offset,4))
1470 accept_state = tvb_get_ntohl(tvb,offset+0);
1472 proto_tree_add_uint(rpc_tree, hf_rpc_state_accept, tvb,
1473 offset+0, 4, accept_state);
1476 switch (accept_state) {
1478 /* go to the next dissector */
1481 if (!tvb_bytes_exist(tvb,offset,8))
1483 vers_low = tvb_get_ntohl(tvb,offset+0);
1484 vers_high = tvb_get_ntohl(tvb,offset+4);
1486 proto_tree_add_uint(rpc_tree,
1487 hf_rpc_programversion_min,
1488 tvb, offset+0, 4, vers_low);
1489 proto_tree_add_uint(rpc_tree,
1490 hf_rpc_programversion_max,
1491 tvb, offset+4, 4, vers_high);
1499 } else if (reply_state == MSG_DENIED) {
1500 if (!tvb_bytes_exist(tvb,offset,4))
1502 reject_state = tvb_get_ntohl(tvb,offset+0);
1504 proto_tree_add_uint(rpc_tree,
1505 hf_rpc_state_reject, tvb, offset+0, 4,
1510 if (reject_state==RPC_MISMATCH) {
1511 if (!tvb_bytes_exist(tvb,offset,8))
1513 vers_low = tvb_get_ntohl(tvb,offset+0);
1514 vers_high = tvb_get_ntohl(tvb,offset+4);
1516 proto_tree_add_uint(rpc_tree,
1518 tvb, offset+0, 4, vers_low);
1519 proto_tree_add_uint(rpc_tree,
1521 tvb, offset+4, 4, vers_high);
1524 } else if (reject_state==AUTH_ERROR) {
1525 if (!tvb_bytes_exist(tvb,offset,4))
1527 auth_state = tvb_get_ntohl(tvb,offset+0);
1529 proto_tree_add_uint(rpc_tree,
1530 hf_rpc_state_auth, tvb, offset+0, 4,
1536 } /* end of RPC reply */
1538 /* now we know, that RPC was shorter */
1540 proto_item_set_len(rpc_item, offset - offset_old);
1543 /* create here the program specific sub-tree */
1545 pitem = proto_tree_add_item(tree, proto, tvb,
1546 offset, tvb_length(tvb) - offset, FALSE);
1548 ptree = proto_item_add_subtree(pitem, ett);
1552 proto_tree_add_uint(ptree,
1553 hf_rpc_programversion, NullTVB, 0, 0, vers);
1554 proto_tree_add_uint_format(ptree,
1555 hf_rpc_procedure, NullTVB, 0, 0, proc,
1556 "Procedure: %s (%u)", procname, proc);
1560 if (!proto_is_protocol_enabled(proto)) {
1561 dissect_function = NULL;
1564 /* RPCSEC_GSS processing. */
1565 if (flavor == RPCSEC_GSS) {
1567 case RPCSEC_GSS_INIT:
1568 case RPCSEC_GSS_CONTINUE_INIT:
1569 if (msg_type == RPC_CALL) {
1570 offset = dissect_rpc_authgss_initarg(tvb,
1571 pinfo, ptree, offset);
1574 offset = dissect_rpc_authgss_initres(tvb,
1575 pinfo, ptree, offset);
1578 case RPCSEC_GSS_DATA:
1579 if (gss_svc == RPCSEC_GSS_SVC_NONE) {
1580 offset = call_dissect_function(tvb,
1581 pinfo, ptree, offset,
1584 else if (gss_svc == RPCSEC_GSS_SVC_INTEGRITY) {
1585 offset = dissect_rpc_authgss_integ_data(tvb,
1586 pinfo, ptree, offset,
1589 else if (gss_svc == RPCSEC_GSS_SVC_PRIVACY) {
1590 offset = dissect_rpc_authgss_priv_data(tvb,
1591 pinfo, ptree, offset);
1595 dissect_function = NULL;
1600 offset=call_dissect_function(tvb, pinfo, ptree, offset,
1604 /* dissect any remaining bytes (incomplete dissection) as pure data in
1606 dissect_data(tvb, offset, pinfo, ptree);
1612 /* Discard any state we've saved. */
1614 rpc_init_protocol(void)
1616 memset(rpc_call_table, '\0', sizeof rpc_call_table);
1618 rpc_call_firstfree = 0;
1622 /* will be called once from register.c at startup time */
1624 proto_register_rpc(void)
1626 static hf_register_info hf[] = {
1627 { &hf_rpc_lastfrag, {
1628 "Last Fragment", "rpc.lastfrag", FT_BOOLEAN, BASE_NONE,
1629 &yesno, 0, "Last Fragment" }},
1630 { &hf_rpc_fraglen, {
1631 "Fragment Length", "rpc.fraglen", FT_UINT32, BASE_DEC,
1632 NULL, 0, "Fragment Length" }},
1634 "XID", "rpc.xid", FT_UINT32, BASE_HEX,
1636 { &hf_rpc_msgtype, {
1637 "Message Type", "rpc.msgtyp", FT_UINT32, BASE_DEC,
1638 VALS(rpc_msg_type), 0, "Message Type" }},
1639 { &hf_rpc_state_reply, {
1640 "Reply State", "rpc.replystat", FT_UINT32, BASE_DEC,
1641 VALS(rpc_reply_state), 0, "Reply State" }},
1642 { &hf_rpc_state_accept, {
1643 "Accept State", "rpc.state_accept", FT_UINT32, BASE_DEC,
1644 VALS(rpc_accept_state), 0, "Accept State" }},
1645 { &hf_rpc_state_reject, {
1646 "Reject State", "rpc.state_reject", FT_UINT32, BASE_DEC,
1647 VALS(rpc_reject_state), 0, "Reject State" }},
1648 { &hf_rpc_state_auth, {
1649 "Auth State", "rpc.state_auth", FT_UINT32, BASE_DEC,
1650 VALS(rpc_auth_state), 0, "Auth State" }},
1651 { &hf_rpc_version, {
1652 "RPC Version", "rpc.version", FT_UINT32, BASE_DEC,
1653 NULL, 0, "RPC Version" }},
1654 { &hf_rpc_version_min, {
1655 "RPC Version (Minimum)", "rpc.version.min", FT_UINT32,
1656 BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1657 { &hf_rpc_version_max, {
1658 "RPC Version (Maximum)", "rpc.version.max", FT_UINT32,
1659 BASE_DEC, NULL, 0, "RPC Version (Maximum)" }},
1660 { &hf_rpc_program, {
1661 "Program", "rpc.program", FT_UINT32, BASE_DEC,
1662 NULL, 0, "Program" }},
1663 { &hf_rpc_programversion, {
1664 "Program Version", "rpc.programversion", FT_UINT32,
1665 BASE_DEC, NULL, 0, "Program Version" }},
1666 { &hf_rpc_programversion_min, {
1667 "Program Version (Minimum)", "rpc.programversion.min", FT_UINT32,
1668 BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1669 { &hf_rpc_programversion_max, {
1670 "Program Version (Maximum)", "rpc.programversion.max", FT_UINT32,
1671 BASE_DEC, NULL, 0, "Program Version (Maximum)" }},
1672 { &hf_rpc_procedure, {
1673 "Procedure", "rpc.procedure", FT_UINT32, BASE_DEC,
1674 NULL, 0, "Procedure" }},
1675 { &hf_rpc_auth_flavor, {
1676 "Flavor", "rpc.auth.flavor", FT_UINT32, BASE_DEC,
1677 VALS(rpc_auth_flavor), 0, "Flavor" }},
1678 { &hf_rpc_auth_length, {
1679 "Length", "rpc.auth.length", FT_UINT32, BASE_DEC,
1680 NULL, 0, "Length" }},
1681 { &hf_rpc_auth_stamp, {
1682 "Stamp", "rpc.auth.stamp", FT_UINT32, BASE_HEX,
1683 NULL, 0, "Stamp" }},
1684 { &hf_rpc_auth_uid, {
1685 "UID", "rpc.auth.uid", FT_UINT32, BASE_DEC,
1687 { &hf_rpc_auth_gid, {
1688 "GID", "rpc.auth.gid", FT_UINT32, BASE_DEC,
1690 { &hf_rpc_authgss_v, {
1691 "GSS Version", "rpc.authgss.version", FT_UINT32,
1692 BASE_DEC, NULL, 0, "GSS Version" }},
1693 { &hf_rpc_authgss_proc, {
1694 "GSS Procedure", "rpc.authgss.procedure", FT_UINT32,
1695 BASE_DEC, VALS(rpc_authgss_proc), 0, "GSS Procedure" }},
1696 { &hf_rpc_authgss_seq, {
1697 "GSS Sequence Number", "rpc.authgss.seqnum", FT_UINT32,
1698 BASE_DEC, NULL, 0, "GSS Sequence Number" }},
1699 { &hf_rpc_authgss_svc, {
1700 "GSS Service", "rpc.authgss.service", FT_UINT32,
1701 BASE_DEC, VALS(rpc_authgss_svc), 0, "GSS Service" }},
1702 { &hf_rpc_authgss_ctx, {
1703 "GSS Context", "rpc.authgss.context", FT_BYTES,
1704 BASE_HEX, NULL, 0, "GSS Context" }},
1705 { &hf_rpc_authgss_major, {
1706 "GSS Major Status", "rpc.authgss.major", FT_UINT32,
1707 BASE_DEC, NULL, 0, "GSS Major Status" }},
1708 { &hf_rpc_authgss_minor, {
1709 "GSS Minor Status", "rpc.authgss.minor", FT_UINT32,
1710 BASE_DEC, NULL, 0, "GSS Minor Status" }},
1711 { &hf_rpc_authgss_window, {
1712 "GSS Sequence Window", "rpc.authgss.window", FT_UINT32,
1713 BASE_DEC, NULL, 0, "GSS Sequence Window" }},
1714 { &hf_rpc_authgss_token, {
1715 "GSS Token", "rpc.authgss.token", FT_BYTES,
1716 BASE_HEX, NULL, 0, "GSS Token" }},
1717 { &hf_rpc_authgss_data_length, {
1718 "Length", "rpc.authgss.data.length", FT_UINT32,
1719 BASE_DEC, NULL, 0, "Length" }},
1720 { &hf_rpc_authgss_data, {
1721 "GSS Data", "rpc.authgss.data", FT_BYTES,
1722 BASE_HEX, NULL, 0, "GSS Data" }},
1723 { &hf_rpc_authgss_checksum, {
1724 "GSS Checksum", "rpc.authgss.checksum", FT_BYTES,
1725 BASE_HEX, NULL, 0, "GSS Checksum" }},
1726 { &hf_rpc_auth_machinename, {
1727 "Machine Name", "rpc.auth.machinename", FT_STRING,
1728 BASE_DEC, NULL, 0, "Machine Name" }},
1730 "Duplicate Transaction", "rpc.dup", FT_UINT32, BASE_DEC,
1731 NULL, 0, "Duplicate Transaction" }},
1732 { &hf_rpc_call_dup, {
1733 "Duplicate Call", "rpc.call.dup", FT_UINT32, BASE_DEC,
1734 NULL, 0, "Duplicate Call" }},
1735 { &hf_rpc_reply_dup, {
1736 "Duplicate Reply", "rpc.reply.dup", FT_UINT32, BASE_DEC,
1737 NULL, 0, "Duplicate Reply" }},
1738 { &hf_rpc_value_follows, {
1739 "Value Follows", "rpc.value_follows", FT_BOOLEAN, BASE_NONE,
1740 &yesno, 0, "Value Follows" }}
1742 static gint *ett[] = {
1750 proto_rpc = proto_register_protocol("Remote Procedure Call",
1752 proto_register_field_array(proto_rpc, hf, array_length(hf));
1753 proto_register_subtree_array(ett, array_length(ett));
1754 register_init_routine(&rpc_init_protocol);
1757 * Init the hash tables. Dissectors for RPC protocols must
1758 * have a "handoff registration" routine that registers the
1759 * protocol with RPC; they must not do it in their protocol
1760 * registration routine, as their protocol registration
1761 * routine might be called before this routine is called and
1762 * thus might be called before the hash tables are initialized,
1763 * but it's guaranteed that all protocol registration routines
1764 * will be called before any handoff registration routines
1767 rpc_progs = g_hash_table_new(rpc_prog_hash, rpc_prog_equal);
1768 rpc_procs = g_hash_table_new(rpc_proc_hash, rpc_proc_equal);
1773 proto_reg_handoff_rpc(void)
1775 heur_dissector_add("tcp", dissect_rpc);
1776 heur_dissector_add("udp", dissect_rpc);