2 * Routines for rpc dissection
3 * Copyright 1999, Uwe Girlich <Uwe.Girlich@philosys.de>
5 * $Id: packet-rpc.c,v 1.26 2000/01/22 05:49:06 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"
45 #define RPC_RM_FRAGLEN 0x7fffffffL
47 static struct true_false_string yesno = { "Yes", "No" };
50 static const value_string rpc_msg_type[3] = {
52 { RPC_REPLY, "Reply" },
56 static const value_string rpc_reply_state[3] = {
57 { MSG_ACCEPTED, "accepted" },
58 { MSG_DENIED, "denied" },
62 const value_string rpc_auth_flavor[] = {
63 { AUTH_NULL, "AUTH_NULL" },
64 { AUTH_UNIX, "AUTH_UNIX" },
65 { AUTH_SHORT, "AUTH_SHORT" },
66 { AUTH_DES, "AUTH_DES" },
70 static const value_string rpc_accept_state[6] = {
71 { SUCCESS, "RPC executed successfully" },
72 { PROG_UNAVAIL, "remote hasn't exported program" },
73 { PROG_MISMATCH, "remote can't support version #" },
74 { PROC_UNAVAIL, "program can't support procedure" },
75 { GARBAGE_ARGS, "procedure can't decode params" },
79 static const value_string rpc_reject_state[3] = {
80 { RPC_MISMATCH, "RPC_MISMATCH" },
81 { AUTH_ERROR, "AUTH_ERROR" },
85 static const value_string rpc_auth_state[6] = {
86 { AUTH_BADCRED, "bad credential (seal broken)" },
87 { AUTH_REJECTEDCRED, "client must begin new session" },
88 { AUTH_BADVERF, "bad verifier (seal broken)" },
89 { AUTH_REJECTEDVERF, "verifier expired or replayed" },
90 { AUTH_TOOWEAK, "rejected for security reasons" },
95 /* the protocol number */
96 static int proto_rpc = -1;
97 static int hf_rpc_lastfrag = -1;
98 static int hf_rpc_fraglen = -1;
99 static int hf_rpc_xid = -1;
100 static int hf_rpc_msgtype = -1;
101 static int hf_rpc_version = -1;
102 static int hf_rpc_version_min = -1;
103 static int hf_rpc_version_max = -1;
104 static int hf_rpc_program = -1;
105 static int hf_rpc_programversion = -1;
106 static int hf_rpc_programversion_min = -1;
107 static int hf_rpc_programversion_max = -1;
108 static int hf_rpc_procedure = -1;
109 static int hf_rpc_auth_flavor = -1;
110 static int hf_rpc_auth_length = -1;
111 static int hf_rpc_auth_machinename = -1;
112 static int hf_rpc_auth_stamp = -1;
113 static int hf_rpc_auth_uid = -1;
114 static int hf_rpc_auth_gid = -1;
115 static int hf_rpc_state_accept = -1;
116 static int hf_rpc_state_reply = -1;
117 static int hf_rpc_state_reject = -1;
118 static int hf_rpc_state_auth = -1;
119 static int hf_rpc_dup = -1;
120 static int hf_rpc_call_dup = -1;
121 static int hf_rpc_reply_dup = -1;
123 static gint ett_rpc = -1;
124 static gint ett_rpc_string = -1;
125 static gint ett_rpc_cred = -1;
126 static gint ett_rpc_verf = -1;
127 static gint ett_rpc_gids = -1;
129 /* Hash table with info on RPC program numbers */
130 static GHashTable *rpc_progs;
132 /* Hash table with info on RPC procedure numbers */
133 static GHashTable *rpc_procs;
136 /***********************************/
137 /* Hash array with procedure names */
138 /***********************************/
142 rpc_proc_equal(gconstpointer k1, gconstpointer k2)
144 rpc_proc_info_key* key1 = (rpc_proc_info_key*) k1;
145 rpc_proc_info_key* key2 = (rpc_proc_info_key*) k2;
147 return ((key1->prog == key2->prog &&
148 key1->vers == key2->vers &&
149 key1->proc == key2->proc) ?
153 /* calculate a hash key */
155 rpc_proc_hash(gconstpointer k)
157 rpc_proc_info_key* key = (rpc_proc_info_key*) k;
159 return (key->prog ^ (key->vers<<16) ^ (key->proc<<24));
163 /* insert some entries */
165 rpc_init_proc_table(guint prog, guint vers, const vsff *proc_table)
169 for (proc = proc_table ; proc->strptr!=NULL; proc++) {
170 rpc_proc_info_key *key;
171 rpc_proc_info_value *value;
173 key = (rpc_proc_info_key *) g_malloc(sizeof(rpc_proc_info_key));
176 key->proc = proc->value;
178 value = (rpc_proc_info_value *) g_malloc(sizeof(rpc_proc_info_value));
179 value->name = proc->strptr;
180 value->dissect_call = proc->dissect_call;
181 value->dissect_reply = proc->dissect_reply;
183 g_hash_table_insert(rpc_procs,key,value);
187 /*----------------------------------------*/
188 /* end of Hash array with procedure names */
189 /*----------------------------------------*/
192 /*********************************/
193 /* Hash array with program names */
194 /*********************************/
198 rpc_prog_equal(gconstpointer k1, gconstpointer k2)
200 rpc_prog_info_key* key1 = (rpc_prog_info_key*) k1;
201 rpc_prog_info_key* key2 = (rpc_prog_info_key*) k2;
203 return ((key1->prog == key2->prog) ?
208 /* calculate a hash key */
210 rpc_prog_hash(gconstpointer k)
212 rpc_prog_info_key* key = (rpc_prog_info_key*) k;
219 rpc_init_prog(int proto, guint32 prog, int ett)
221 rpc_prog_info_key *key;
222 rpc_prog_info_value *value;
223 char *uc_progname = NULL, *lc_progname = NULL;
225 key = (rpc_prog_info_key *) g_malloc(sizeof(rpc_prog_info_key));
228 value = (rpc_prog_info_value *) g_malloc(sizeof(rpc_prog_info_value));
229 value->proto = proto;
232 lc_progname = proto_registrar_get_abbrev(proto);
236 uc_progname = strdup(lc_progname);
237 for (i=0; i<strlen(uc_progname); i++)
239 uc_progname[i] = toupper(uc_progname[i]);
242 value->progname = uc_progname;
244 g_hash_table_insert(rpc_progs,key,value);
247 /* return the name associated with a previously registered program. This
248 should probably eventually be expanded to use the rpc YP/NIS map
249 so that it can give names for programs not handled by ethereal */
250 char *rpc_prog_name(guint32 prog)
252 char *progname = NULL;
253 rpc_prog_info_key rpc_prog_key;
254 rpc_prog_info_value *rpc_prog;
256 rpc_prog_key.prog = prog;
257 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
258 progname = "Unknown";
261 progname = rpc_prog->progname;
267 /*--------------------------------------*/
268 /* end of Hash array with program names */
269 /*--------------------------------------*/
273 * Init the hash tables. It will be called from ethereal_proto_init().
274 * ethereal_proto_init() calls later proto_init(), which calls
275 * register_all_protocols().
276 * The proto_register_<some rpc program> functions use these hash tables
277 * here, so we need this order!
282 rpc_progs = g_hash_table_new(rpc_prog_hash, rpc_prog_equal);
283 rpc_procs = g_hash_table_new(rpc_proc_hash, rpc_proc_equal);
287 /* static array, first quick implementation, I'll switch over to GList soon */
288 rpc_call_info rpc_call_table[RPC_CALL_TABLE_LENGTH];
289 guint32 rpc_call_index = 0;
290 guint32 rpc_call_firstfree = 0;
293 rpc_call_insert(rpc_call_info *call)
295 /* some space left? */
296 if (rpc_call_firstfree<RPC_CALL_TABLE_LENGTH) {
297 /* some space left */
298 /* take the first free entry */
299 rpc_call_index = rpc_call_firstfree;
300 /* increase this limit */
301 rpc_call_firstfree++;
302 /* rpc_call_firstfree may now be RPC_CALL_TABLE_LENGTH */
306 /* the next entry, with wrap around */
307 rpc_call_index = (rpc_call_index+1) % rpc_call_firstfree;
310 /* put the entry in */
311 memcpy(&rpc_call_table[rpc_call_index],call,sizeof(*call));
317 rpc_call_lookup(rpc_call_info *call)
324 rpc_call_table[i].xid == call->xid &&
325 rpc_call_table[i].conversation == call->conversation
327 return &rpc_call_table[i];
329 if (rpc_call_firstfree) {
330 /* decrement by one, go to rpc_call_firstfree-1
331 at the start of the list */
332 i = (i-1+rpc_call_firstfree) % rpc_call_firstfree;
334 } while (i!=rpc_call_index);
340 rpc_roundup(unsigned int a)
342 unsigned int mod = a % 4;
343 return a + ((mod)? 4-mod : 0);
348 dissect_rpc_bool(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
353 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
354 value = EXTRACT_UINT(pd, offset+0);
356 proto_tree_add_item(tree, hfindex, offset, 4, value);
364 dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
365 char* name, char* type)
369 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
370 value = EXTRACT_UINT(pd, offset+0);
373 proto_tree_add_text(tree, offset, 4,
374 "%s: %u", name, value);
383 dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
384 char* name, char* type)
389 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
390 value_high = EXTRACT_UINT(pd, offset+0);
391 value_low = EXTRACT_UINT(pd, offset+4);
395 proto_tree_add_text(tree, offset, 8,
396 "%s: 0x%x%08x", name, value_high, value_low);
398 proto_tree_add_text(tree, offset, 8,
399 "%s: %u", name, value_low);
408 dissect_rpc_opaque_data(const u_char *pd, int offset, frame_data *fd,
409 proto_tree *tree, int hfindex, gboolean string_data,
410 char **string_buffer_ret)
412 proto_item *string_item = NULL;
413 proto_tree *string_tree = NULL;
414 int old_offset = offset;
416 int length_truncated = 0;
418 int string_truncated = 0;
419 guint32 string_length = 0;
420 guint32 string_length_full;
421 guint32 string_length_packet;
422 guint32 string_length_copy = 0;
424 int fill_truncated = 0;
425 guint32 fill_length = 0;
426 guint32 fill_length_packet = 0;
427 guint32 fill_length_copy = 0;
429 char *string_buffer = NULL;
430 char *string_buffer_print = NULL;
432 if (BYTES_ARE_IN_FRAME(offset,4)) {
433 string_length = EXTRACT_UINT(pd,offset+0);
434 string_length_full = rpc_roundup(string_length);
435 string_length_packet = pi.captured_len - (offset + 4);
436 if (string_length_packet < string_length) {
437 /* truncated string */
438 string_truncated = 1;
439 string_length_copy = string_length_packet;
442 fill_length_packet = 0;
443 fill_length_copy = 0;
446 /* full string data */
447 string_truncated = 0;
448 string_length_copy = string_length;
449 fill_length = string_length_full - string_length;
450 fill_length_packet = pi.captured_len - (offset + 4 + string_length);
451 if (fill_length_packet < fill_length) {
452 /* truncated fill bytes */
453 fill_length_copy = fill_length_packet;
457 /* full fill bytes */
458 fill_length_copy = fill_length;
462 string_buffer = (char*)g_malloc(string_length_copy +
463 (string_data ? 1 : 0));
464 memcpy(string_buffer,pd+offset+4,string_length_copy);
466 string_buffer[string_length_copy] = '\0';
468 /* calculate a nice printable string */
470 if (string_length != string_length_copy) {
472 /* alloc maximum data area */
473 string_buffer_print = (char*)g_malloc(string_length_copy + 12 + 1);
474 /* copy over the data */
475 memcpy(string_buffer_print,string_buffer,string_length_copy);
476 /* append a 0 byte for sure printing */
477 string_buffer_print[string_length_copy] = '\0';
478 /* append <TRUNCATED> */
479 /* This way, we get the TRUNCATED even
480 in the case of totally wrong packets,
481 where \0 are inside the string.
482 TRUNCATED will appear at the
483 first \0 or at the end (where we
484 put the securing \0).
486 strcat(string_buffer_print,"<TRUNCATED>");
489 string_buffer_print = g_strdup("<DATA><TRUNCATED>");
494 string_buffer_print = g_strdup(string_buffer);
497 string_buffer_print = g_strdup("<DATA>");
502 string_buffer_print = g_strdup("<EMPTY>");
506 length_truncated = 1;
507 string_truncated = 2;
509 string_buffer = g_strdup("");
510 string_buffer_print = g_strdup("<TRUNCATED>");
514 string_item = proto_tree_add_text(tree,offset+0, END_OF_FRAME,
515 "%s: %s", proto_registrar_get_name(hfindex), string_buffer_print);
517 proto_tree_add_item_hidden(tree, hfindex, offset+4,
518 string_length_copy, string_buffer);
521 string_tree = proto_item_add_subtree(string_item, ett_rpc_string);
524 if (length_truncated) {
526 proto_tree_add_text(string_tree,
527 offset,pi.captured_len-offset,
528 "length: <TRUNCATED>");
529 offset = pi.captured_len;
532 proto_tree_add_text(string_tree,offset+0,4,
533 "length: %u", string_length);
537 proto_tree_add_text(string_tree,offset,string_length_copy,
538 "contents: %s", string_buffer_print);
539 offset += string_length_copy;
542 if (fill_truncated) {
543 proto_tree_add_text(string_tree,
544 offset,fill_length_copy,
545 "fill bytes: opaque data<TRUNCATED>");
548 proto_tree_add_text(string_tree,
549 offset,fill_length_copy,
550 "fill bytes: opaque data");
553 offset += fill_length_copy;
558 proto_item_set_len(string_item, offset - old_offset);
561 if (string_buffer != NULL) g_free (string_buffer );
562 if (string_buffer_print != NULL) {
563 if (string_buffer_ret != NULL)
564 *string_buffer_ret = string_buffer_print;
566 g_free (string_buffer_print);
573 dissect_rpc_string(const u_char *pd, int offset, frame_data *fd,
574 proto_tree *tree, int hfindex, char **string_buffer_ret)
576 offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, TRUE,
584 dissect_rpc_data(const u_char *pd, int offset, frame_data *fd,
585 proto_tree *tree, int hfindex)
587 offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, FALSE,
595 dissect_rpc_auth( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
601 /* both checks are made outside */
602 /* if (!BYTES_ARE_IN_FRAME(offset,8)) return; */
603 flavor = EXTRACT_UINT(pd,offset+0);
604 length = EXTRACT_UINT(pd,offset+4);
605 length_full = rpc_roundup(length);
606 /* if (!BYTES_ARE_IN_FRAME(offset+8,full_length)) return; */
609 proto_tree_add_item(tree, hf_rpc_auth_flavor, offset+0, 4,
611 proto_tree_add_item(tree, hf_rpc_auth_length, offset+4, 4,
626 proto_tree *gtree = NULL;
628 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
629 stamp = EXTRACT_UINT(pd,offset+0);
631 proto_tree_add_item(tree, hf_rpc_auth_stamp,
635 offset = dissect_rpc_string(pd,offset,fd,
636 tree,hf_rpc_auth_machinename,NULL);
638 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
639 uid = EXTRACT_UINT(pd,offset+0);
641 proto_tree_add_item(tree, hf_rpc_auth_uid,
645 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
646 gid = EXTRACT_UINT(pd,offset+0);
648 proto_tree_add_item(tree, hf_rpc_auth_gid,
652 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
653 gids_count = EXTRACT_UINT(pd,offset+0);
655 gitem = proto_tree_add_text(tree, offset, 4+gids_count*4,
657 gtree = proto_item_add_subtree(gitem, ett_rpc_gids);
660 if (!BYTES_ARE_IN_FRAME(offset,4*gids_count)) return;
661 for (gids_i = 0 ; gids_i < gids_count ; gids_i++) {
662 gids_entry = EXTRACT_UINT(pd,offset+0);
664 proto_tree_add_item(gtree, hf_rpc_auth_gid,
665 offset, 4, gids_entry);
668 /* how can I NOW change the gitem to print a list with
669 the first 16 gids? */
677 /* I have no tcpdump file with such a packet to verify the
678 info from the RFC 1050 */
687 proto_tree_add_text(tree,offset,
688 length_full, "opaque data");
694 dissect_rpc_cred( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
701 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
702 length = EXTRACT_UINT(pd,offset+4);
703 length_full = rpc_roundup(length);
704 if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
707 citem = proto_tree_add_text(tree, offset, 8+length_full,
709 ctree = proto_item_add_subtree(citem, ett_rpc_cred);
710 dissect_rpc_auth(pd, offset, fd, ctree);
712 offset += 8 + length_full;
719 dissect_rpc_verf( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
722 unsigned int length_full;
726 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
727 length = EXTRACT_UINT(pd,offset+4);
728 length_full = rpc_roundup(length);
729 if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
732 vitem = proto_tree_add_text(tree, offset, 8+length_full,
734 vtree = proto_item_add_subtree(vitem, ett_rpc_verf);
735 dissect_rpc_auth(pd, offset, fd, vtree);
737 offset += 8 + length_full;
744 dissect_rpc( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
747 rpc_call_info rpc_key;
748 rpc_call_info *rpc_call = NULL;
749 rpc_prog_info_value *rpc_prog = NULL;
750 rpc_prog_info_key rpc_prog_key;
753 unsigned int rpcvers;
754 unsigned int prog = 0;
755 unsigned int vers = 0;
756 unsigned int proc = 0;
760 unsigned int reply_state;
761 unsigned int accept_state;
762 unsigned int reject_state;
764 char *msg_type_name = NULL;
766 char *procname = NULL;
767 static char procname_static[20];
769 unsigned int vers_low;
770 unsigned int vers_high;
772 unsigned int auth_state;
774 proto_item *rpc_item=NULL;
775 proto_tree *rpc_tree = NULL;
777 proto_item *pitem=NULL;
778 proto_tree *ptree = NULL;
779 int offset_old = offset;
784 rpc_call_info rpc_call_msg;
785 rpc_proc_info_key key;
786 rpc_proc_info_value *value = NULL;
787 conversation_t* conversation;
788 static address null_address = { AT_NONE, 0, NULL };
790 dissect_function_t *dissect_function = NULL;
792 /* TCP uses record marking */
793 use_rm = (pi.ptype == PT_TCP);
795 /* the first 4 bytes are special in "record marking mode" */
797 if (!BYTES_ARE_IN_FRAME(offset,4))
799 rpc_rm = EXTRACT_UINT(pd,offset);
804 * Check to see whether this looks like an RPC call or reply.
806 if (!BYTES_ARE_IN_FRAME(offset,8)) {
807 /* Captured data in packet isn't enough to let us tell. */
811 /* both directions need at least this */
812 msg_type = EXTRACT_UINT(pd,offset+4);
817 /* check for RPC call */
818 if (!BYTES_ARE_IN_FRAME(offset,16)) {
819 /* Captured data in packet isn't enough to let us
824 /* XID can be anything, we don't check it.
825 We already have the message type.
826 Check whether an RPC version number of 2 is in the
827 location where it would be, and that an RPC program
828 number we know about is in the locaton where it would be. */
829 rpc_prog_key.prog = EXTRACT_UINT(pd,offset+12);
830 if (EXTRACT_UINT(pd,offset+8) != 2 ||
831 ((rpc_prog = g_hash_table_lookup(rpc_progs, &rpc_prog_key))
833 /* They're not, so it's probably not an RPC call. */
839 /* Check for RPC reply. A reply must match a call that
840 we've seen, and the reply must be sent to the same
841 port and address that the call came from, and must
842 come from the port to which the call was sent. (We
843 don't worry about the address to which the call was
844 sent and from which the reply was sent, because there's
845 no guarantee that the reply will come from the address
846 to which the call was sent.) */
847 conversation = find_conversation(&null_address, &pi.dst,
848 pi.ptype, pi.srcport, pi.destport);
849 if (conversation == NULL) {
850 /* We haven't seen an RPC call for that conversation,
851 so we can't check for a reply to that call. */
855 /* The XIDs of the call and reply must match. */
856 rpc_key.xid = EXTRACT_UINT(pd,offset+0);
857 rpc_key.conversation = conversation;
858 if ((rpc_call = rpc_call_lookup(&rpc_key)) == NULL) {
859 /* The XID doesn't match a call from that
860 conversation, so it's probably not an RPC reply. */
866 /* The putative message type field contains neither
867 RPC_CALL nor RPC_REPLY, so it's not an RPC call or
872 if (check_col(fd, COL_PROTOCOL))
873 col_add_str(fd, COL_PROTOCOL, "RPC");
876 rpc_item = proto_tree_add_item(tree, proto_rpc, offset, END_OF_FRAME, NULL);
878 rpc_tree = proto_item_add_subtree(rpc_item, ett_rpc);
882 if (use_rm && rpc_tree) {
883 proto_tree_add_item(rpc_tree,hf_rpc_lastfrag,
884 offset-4, 4, (rpc_rm >> 31) & 0x1);
885 proto_tree_add_item(rpc_tree,hf_rpc_fraglen,
886 offset-4, 4, rpc_rm & RPC_RM_FRAGLEN);
889 xid = EXTRACT_UINT(pd,offset+0);
891 proto_tree_add_item_format(rpc_tree,hf_rpc_xid,
892 offset+0, 4, xid, "XID: 0x%x (%u)", xid, xid);
895 msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u");
897 proto_tree_add_item(rpc_tree, hf_rpc_msgtype,
898 offset+4, 4, msg_type);
903 if (msg_type==RPC_CALL) {
904 /* we know already the proto-entry, the ETT-const,
906 proto = rpc_prog->proto;
908 progname = rpc_prog->progname;
910 rpcvers = EXTRACT_UINT(pd,offset+0);
912 proto_tree_add_item(rpc_tree,
913 hf_rpc_version, offset+0, 4, rpcvers);
916 prog = EXTRACT_UINT(pd,offset+4);
919 proto_tree_add_item_format(rpc_tree,
920 hf_rpc_program, offset+4, 4, prog,
921 "Program: %s (%u)", progname, prog);
924 if (check_col(fd, COL_PROTOCOL)) {
925 /* Set the protocol name to the underlying
927 col_add_fstr(fd, COL_PROTOCOL, "%s", progname);
930 if (!BYTES_ARE_IN_FRAME(offset+8,4))
932 vers = EXTRACT_UINT(pd,offset+8);
934 proto_tree_add_item(rpc_tree,
935 hf_rpc_programversion, offset+8, 4, vers);
938 if (!BYTES_ARE_IN_FRAME(offset+12,4))
940 proc = EXTRACT_UINT(pd,offset+12);
946 value = g_hash_table_lookup(rpc_procs,&key);
948 dissect_function = value->dissect_call;
949 procname = value->name;
952 /* happens only with strange program versions or
953 non-existing dissectors */
954 dissect_function = NULL;
955 sprintf(procname_static, "proc-%u", proc);
956 procname = procname_static;
959 proto_tree_add_item_format(rpc_tree,
960 hf_rpc_procedure, offset+12, 4, proc,
961 "Procedure: %s (%u)", procname, proc);
964 if (check_col(fd, COL_INFO)) {
965 col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
972 /* Keep track of the address and port whence the call came,
973 and the port to which the call is being sent, so that
974 we can match up calls wityh replies. (We don't worry
975 about the address to which the call was sent and from
976 which the reply was sent, because there's no
977 guarantee that the reply will come from the address
978 to which the call was sent.) */
979 conversation = find_conversation(&pi.src, &null_address,
980 pi.ptype, pi.srcport, pi.destport);
981 if (conversation == NULL) {
982 /* It's not part of any conversation - create a new one. */
983 conversation = conversation_new(&pi.src, &null_address,
984 pi.ptype, pi.srcport, pi.destport, NULL);
987 /* prepare the key data */
988 rpc_call_msg.xid = xid;
989 rpc_call_msg.conversation = conversation;
991 /* look up the request */
992 if (rpc_call_lookup(&rpc_call_msg)) {
993 /* duplicate request */
994 if (check_col(fd, COL_INFO)) {
995 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
997 proto_tree_add_item_hidden(rpc_tree,
998 hf_rpc_dup, 0,0, xid);
999 proto_tree_add_item_hidden(rpc_tree,
1000 hf_rpc_call_dup, 0,0, xid);
1005 /* prepare the value data */
1006 rpc_call_msg.replies = 0;
1007 rpc_call_msg.prog = prog;
1008 rpc_call_msg.vers = vers;
1009 rpc_call_msg.proc = proc;
1010 rpc_call_msg.proc_info = value;
1012 rpc_call_insert(&rpc_call_msg);
1017 offset = dissect_rpc_cred(pd, offset, fd, rpc_tree);
1018 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1020 /* go to the next dissector */
1021 /* goto dissect_rpc_prog; */
1023 } /* end of RPC call */
1024 else if (msg_type == RPC_REPLY)
1026 /* we know already the type from the calling routine,
1027 and we already have "rpc_call" set above. */
1028 prog = rpc_call->prog;
1029 vers = rpc_call->vers;
1030 proc = rpc_call->proc;
1031 if (rpc_call->proc_info != NULL) {
1032 dissect_function = rpc_call->proc_info->dissect_reply;
1033 if (rpc_call->proc_info->name != NULL) {
1034 procname = rpc_call->proc_info->name;
1037 sprintf(procname_static, "proc-%u", proc);
1038 procname = procname_static;
1042 dissect_function = NULL;
1043 sprintf(procname_static, "proc-%u", proc);
1044 procname = procname_static;
1046 rpc_call->replies++;
1048 rpc_prog_key.prog = prog;
1049 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
1052 progname = "Unknown";
1055 proto = rpc_prog->proto;
1056 ett = rpc_prog->ett;
1057 progname = rpc_prog->progname;
1059 if (check_col(fd, COL_PROTOCOL)) {
1060 /* Set the protocol name to the underlying
1062 col_add_fstr(fd, COL_PROTOCOL, "%s",
1067 if (check_col(fd, COL_INFO)) {
1068 col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
1076 proto_tree_add_item_format(rpc_tree,
1077 hf_rpc_program, 0, 0, prog,
1078 "Program: %s (%u)", progname, prog);
1079 proto_tree_add_item(rpc_tree,
1080 hf_rpc_programversion, 0, 0, vers);
1081 proto_tree_add_item_format(rpc_tree,
1082 hf_rpc_procedure, 0, 0, proc,
1083 "Procedure: %s (%u)", procname, proc);
1086 if (rpc_call->replies>1) {
1087 if (check_col(fd, COL_INFO)) {
1088 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
1090 proto_tree_add_item_hidden(rpc_tree,
1091 hf_rpc_dup, 0,0, xid);
1092 proto_tree_add_item_hidden(rpc_tree,
1093 hf_rpc_reply_dup, 0,0, xid);
1098 if (!BYTES_ARE_IN_FRAME(offset,4))
1100 reply_state = EXTRACT_UINT(pd,offset+0);
1102 proto_tree_add_item(rpc_tree, hf_rpc_state_reply,
1103 offset+0, 4, reply_state);
1107 if (reply_state == MSG_ACCEPTED) {
1108 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1109 if (!BYTES_ARE_IN_FRAME(offset,4))
1111 accept_state = EXTRACT_UINT(pd,offset+0);
1113 proto_tree_add_item(rpc_tree, hf_rpc_state_accept,
1114 offset+0, 4, accept_state);
1117 switch (accept_state) {
1119 /* now goto the lower protocol */
1120 goto dissect_rpc_prog;
1123 if (!BYTES_ARE_IN_FRAME(offset,8))
1125 vers_low = EXTRACT_UINT(pd,offset+0);
1126 vers_high = EXTRACT_UINT(pd,offset+4);
1128 proto_tree_add_item(rpc_tree,
1129 hf_rpc_programversion_min,
1130 offset+0, 4, vers_low);
1131 proto_tree_add_item(rpc_tree,
1132 hf_rpc_programversion_max,
1133 offset+4, 4, vers_high);
1141 } else if (reply_state == MSG_DENIED) {
1142 if (!BYTES_ARE_IN_FRAME(offset,4))
1144 reject_state = EXTRACT_UINT(pd,offset+0);
1146 proto_tree_add_item(rpc_tree,
1147 hf_rpc_state_reject, offset+0, 4,
1152 if (reject_state==RPC_MISMATCH) {
1153 if (!BYTES_ARE_IN_FRAME(offset,8))
1155 vers_low = EXTRACT_UINT(pd,offset+0);
1156 vers_high = EXTRACT_UINT(pd,offset+4);
1158 proto_tree_add_item(rpc_tree,
1160 offset+0, 4, vers_low);
1161 proto_tree_add_item(rpc_tree,
1163 offset+4, 4, vers_high);
1166 } else if (reject_state==AUTH_ERROR) {
1167 if (!BYTES_ARE_IN_FRAME(offset,4))
1169 auth_state = EXTRACT_UINT(pd,offset+0);
1171 proto_tree_add_item(rpc_tree,
1172 hf_rpc_state_auth, offset+0, 4,
1178 } /* end of RPC reply */
1181 /* I know, goto is evil but it works as it is. */
1183 /* now we know, that RPC was shorter */
1185 proto_item_set_len(rpc_item, offset - offset_old);
1188 /* create here the program specific sub-tree */
1190 pitem = proto_tree_add_item(tree, proto, offset, END_OF_FRAME);
1192 ptree = proto_item_add_subtree(pitem, ett);
1196 proto_tree_add_item(ptree,
1197 hf_rpc_programversion, 0, 0, vers);
1198 proto_tree_add_item_format(ptree,
1199 hf_rpc_procedure, 0, 0, proc,
1200 "Procedure: %s (%u)", procname, proc);
1204 /* call a specific dissection */
1205 if (dissect_function != NULL) {
1206 offset = dissect_function(pd, offset, fd, ptree);
1209 /* dissect any remaining bytes (incomplete dissection) as pure data in
1211 dissect_data(pd, offset, fd, ptree);
1217 /* Discard any state we've saved. */
1219 rpc_init_protocol(void)
1221 memset(rpc_call_table, '\0', sizeof rpc_call_table);
1223 rpc_call_firstfree = 0;
1227 /* will be called once from register.c at startup time */
1229 proto_register_rpc(void)
1231 static hf_register_info hf[] = {
1232 { &hf_rpc_lastfrag, {
1233 "Last Fragment", "rpc.lastfrag", FT_BOOLEAN, BASE_NONE,
1234 &yesno, 0, "Last Fragment" }},
1235 { &hf_rpc_fraglen, {
1236 "Fragment Length", "rpc.fraglen", FT_UINT32, BASE_DEC,
1237 NULL, 0, "Fragment Length" }},
1239 "XID", "rpc.xid", FT_UINT32, BASE_HEX,
1241 { &hf_rpc_msgtype, {
1242 "Message Type", "rpc.msgtyp", FT_UINT32, BASE_DEC,
1243 VALS(rpc_msg_type), 0, "Message Type" }},
1244 { &hf_rpc_state_reply, {
1245 "Reply State", "rpc.replystat", FT_UINT32, BASE_DEC,
1246 VALS(rpc_reply_state), 0, "Reply State" }},
1247 { &hf_rpc_state_accept, {
1248 "Accept State", "rpc.state_accept", FT_UINT32, BASE_DEC,
1249 VALS(rpc_accept_state), 0, "Accept State" }},
1250 { &hf_rpc_state_reject, {
1251 "Reject State", "rpc.state_reject", FT_UINT32, BASE_DEC,
1252 VALS(rpc_reject_state), 0, "Reject State" }},
1253 { &hf_rpc_state_auth, {
1254 "Auth State", "rpc.state_auth", FT_UINT32, BASE_DEC,
1255 VALS(rpc_auth_state), 0, "Auth State" }},
1256 { &hf_rpc_version, {
1257 "RPC Version", "rpc.version", FT_UINT32, BASE_DEC,
1258 NULL, 0, "RPC Version" }},
1259 { &hf_rpc_version_min, {
1260 "RPC Version (Minimum)", "rpc.version.min", FT_UINT32,
1261 BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1262 { &hf_rpc_version_max, {
1263 "RPC Version (Maximum)", "rpc.version.max", FT_UINT32,
1264 BASE_DEC, NULL, 0, "RPC Version (Maximum)" }},
1265 { &hf_rpc_program, {
1266 "Program", "rpc.program", FT_UINT32, BASE_DEC,
1267 NULL, 0, "Program" }},
1268 { &hf_rpc_programversion, {
1269 "Program Version", "rpc.programversion", FT_UINT32,
1270 BASE_DEC, NULL, 0, "Program Version" }},
1271 { &hf_rpc_programversion_min, {
1272 "Program Version (Minimum)", "rpc.programversion.min", FT_UINT32,
1273 BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1274 { &hf_rpc_programversion_max, {
1275 "Program Version (Maximum)", "rpc.programversion.max", FT_UINT32,
1276 BASE_DEC, NULL, 0, "Program Version (Maximum)" }},
1277 { &hf_rpc_procedure, {
1278 "Procedure", "rpc.procedure", FT_UINT32, BASE_DEC,
1279 NULL, 0, "Procedure" }},
1280 { &hf_rpc_auth_flavor, {
1281 "Flavor", "rpc.auth.flavor", FT_UINT32, BASE_DEC,
1282 VALS(rpc_auth_flavor), 0, "Flavor" }},
1283 { &hf_rpc_auth_length, {
1284 "Length", "rpc.auth.length", FT_UINT32, BASE_DEC,
1285 NULL, 0, "Length" }},
1286 { &hf_rpc_auth_stamp, {
1287 "Stamp", "rpc.auth.stamp", FT_UINT32, BASE_HEX,
1288 NULL, 0, "Stamp" }},
1289 { &hf_rpc_auth_uid, {
1290 "UID", "rpc.auth.uid", FT_UINT32, BASE_DEC,
1292 { &hf_rpc_auth_gid, {
1293 "GID", "rpc.auth.gid", FT_UINT32, BASE_DEC,
1295 { &hf_rpc_auth_machinename, {
1296 "Machine Name", "rpc.auth.machinename", FT_STRING,
1297 BASE_DEC, NULL, 0, "Machine Name" }},
1299 "Duplicate Transaction", "rpc.dup", FT_UINT32, BASE_DEC,
1300 NULL, 0, "Duplicate Transaction" }},
1301 { &hf_rpc_call_dup, {
1302 "Duplicate Call", "rpc.call.dup", FT_UINT32, BASE_DEC,
1303 NULL, 0, "Duplicate Call" }},
1304 { &hf_rpc_reply_dup, {
1305 "Duplicate Reply", "rpc.reply.dup", FT_UINT32, BASE_DEC,
1306 NULL, 0, "Duplicate Reply" }}
1308 static gint *ett[] = {
1316 proto_rpc = proto_register_protocol("Remote Procedure Call", "rpc");
1317 proto_register_field_array(proto_rpc, hf, array_length(hf));
1318 proto_register_subtree_array(ett, array_length(ett));
1319 register_init_routine(&rpc_init_protocol);