2 * Routines for rpc dissection
3 * Copyright 1999, Uwe Girlich <Uwe.Girlich@philosys.de>
5 * $Id: packet-rpc.c,v 1.25 2000/01/07 22:05:36 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, proto_tree *tree, int hfindex, int string_data)
410 proto_item *string_item = NULL;
411 proto_tree *string_tree = NULL;
412 int old_offset = offset;
414 int length_truncated = 0;
416 int string_truncated = 0;
417 guint32 string_length = 0;
418 guint32 string_length_full;
419 guint32 string_length_packet;
420 guint32 string_length_copy = 0;
422 int fill_truncated = 0;
423 guint32 fill_length = 0;
424 guint32 fill_length_packet = 0;
425 guint32 fill_length_copy = 0;
427 char *string_buffer = NULL;
428 char *string_buffer_print = NULL;
430 if (BYTES_ARE_IN_FRAME(offset,4)) {
431 string_length = EXTRACT_UINT(pd,offset+0);
432 string_length_full = rpc_roundup(string_length);
433 string_length_packet = pi.captured_len - (offset + 4);
434 if (string_length_packet < string_length) {
435 /* truncated string */
436 string_truncated = 1;
437 string_length_copy = string_length_packet;
440 fill_length_packet = 0;
441 fill_length_copy = 0;
444 /* full string data */
445 string_truncated = 0;
446 string_length_copy = string_length;
447 fill_length = string_length_full - string_length;
448 fill_length_packet = pi.captured_len - (offset + 4 + string_length);
449 if (fill_length_packet < fill_length) {
450 /* truncated fill bytes */
451 fill_length_copy = fill_length_packet;
455 /* full fill bytes */
456 fill_length_copy = fill_length;
460 string_buffer = (char*)g_malloc(string_length_copy +
461 (string_data ? 1 : 0));
462 memcpy(string_buffer,pd+offset+4,string_length_copy);
464 string_buffer[string_length_copy] = '\0';
466 /* calculate a nice printable string */
468 if (string_length != string_length_copy) {
470 /* alloc maximum data area */
471 string_buffer_print = (char*)g_malloc(string_length_copy + 12 + 1);
472 /* copy over the data */
473 memcpy(string_buffer_print,string_buffer,string_length_copy);
474 /* append a 0 byte for sure printing */
475 string_buffer_print[string_length_copy] = '\0';
476 /* append <TRUNCATED> */
477 /* This way, we get the TRUNCATED even
478 in the case of totally wrong packets,
479 where \0 are inside the string.
480 TRUNCATED will appear at the
481 first \0 or at the end (where we
482 put the securing \0).
484 strcat(string_buffer_print,"<TRUNCATED>");
487 string_buffer_print = g_strdup("<DATA><TRUNCATED>");
492 string_buffer_print = g_strdup(string_buffer);
495 string_buffer_print = g_strdup("<DATA>");
500 string_buffer_print = g_strdup("<EMPTY>");
504 length_truncated = 1;
505 string_truncated = 2;
507 string_buffer = g_strdup("");
508 string_buffer_print = g_strdup("<TRUNCATED>");
512 string_item = proto_tree_add_text(tree,offset+0, END_OF_FRAME,
513 "%s: %s", proto_registrar_get_name(hfindex), string_buffer_print);
515 proto_tree_add_item_hidden(tree, hfindex, offset+4,
516 string_length_copy, string_buffer);
519 string_tree = proto_item_add_subtree(string_item, ett_rpc_string);
522 if (length_truncated) {
524 proto_tree_add_text(string_tree,
525 offset,pi.captured_len-offset,
526 "length: <TRUNCATED>");
527 offset = pi.captured_len;
530 proto_tree_add_text(string_tree,offset+0,4,
531 "length: %u", string_length);
535 proto_tree_add_text(string_tree,offset,string_length_copy,
536 "contents: %s", string_buffer_print);
537 offset += string_length_copy;
540 if (fill_truncated) {
541 proto_tree_add_text(string_tree,
542 offset,fill_length_copy,
543 "fill bytes: opaque data<TRUNCATED>");
546 proto_tree_add_text(string_tree,
547 offset,fill_length_copy,
548 "fill bytes: opaque data");
551 offset += fill_length_copy;
556 proto_item_set_len(string_item, offset - old_offset);
559 if (string_buffer != NULL) g_free (string_buffer );
560 if (string_buffer_print != NULL) g_free (string_buffer_print);
566 dissect_rpc_string(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hfindex)
568 offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, 1);
575 dissect_rpc_data(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hfindex)
577 offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, 0);
584 dissect_rpc_auth( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
590 /* both checks are made outside */
591 /* if (!BYTES_ARE_IN_FRAME(offset,8)) return; */
592 flavor = EXTRACT_UINT(pd,offset+0);
593 length = EXTRACT_UINT(pd,offset+4);
594 length_full = rpc_roundup(length);
595 /* if (!BYTES_ARE_IN_FRAME(offset+8,full_length)) return; */
598 proto_tree_add_item(tree, hf_rpc_auth_flavor, offset+0, 4,
600 proto_tree_add_item(tree, hf_rpc_auth_length, offset+4, 4,
615 proto_tree *gtree = NULL;
617 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
618 stamp = EXTRACT_UINT(pd,offset+0);
620 proto_tree_add_item(tree, hf_rpc_auth_stamp,
624 offset = dissect_rpc_string(pd,offset,fd,
625 tree,hf_rpc_auth_machinename);
627 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
628 uid = EXTRACT_UINT(pd,offset+0);
630 proto_tree_add_item(tree, hf_rpc_auth_uid,
634 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
635 gid = EXTRACT_UINT(pd,offset+0);
637 proto_tree_add_item(tree, hf_rpc_auth_gid,
641 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
642 gids_count = EXTRACT_UINT(pd,offset+0);
644 gitem = proto_tree_add_text(tree, offset, 4+gids_count*4,
646 gtree = proto_item_add_subtree(gitem, ett_rpc_gids);
649 if (!BYTES_ARE_IN_FRAME(offset,4*gids_count)) return;
650 for (gids_i = 0 ; gids_i < gids_count ; gids_i++) {
651 gids_entry = EXTRACT_UINT(pd,offset+0);
653 proto_tree_add_item(gtree, hf_rpc_auth_gid,
654 offset, 4, gids_entry);
657 /* how can I NOW change the gitem to print a list with
658 the first 16 gids? */
666 /* I have no tcpdump file with such a packet to verify the
667 info from the RFC 1050 */
676 proto_tree_add_text(tree,offset,
677 length_full, "opaque data");
683 dissect_rpc_cred( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
690 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
691 length = EXTRACT_UINT(pd,offset+4);
692 length_full = rpc_roundup(length);
693 if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
696 citem = proto_tree_add_text(tree, offset, 8+length_full,
698 ctree = proto_item_add_subtree(citem, ett_rpc_cred);
699 dissect_rpc_auth(pd, offset, fd, ctree);
701 offset += 8 + length_full;
708 dissect_rpc_verf( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
711 unsigned int length_full;
715 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
716 length = EXTRACT_UINT(pd,offset+4);
717 length_full = rpc_roundup(length);
718 if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
721 vitem = proto_tree_add_text(tree, offset, 8+length_full,
723 vtree = proto_item_add_subtree(vitem, ett_rpc_verf);
724 dissect_rpc_auth(pd, offset, fd, vtree);
726 offset += 8 + length_full;
733 dissect_rpc( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
736 rpc_call_info rpc_key;
737 rpc_call_info *rpc_call = NULL;
738 rpc_prog_info_value *rpc_prog = NULL;
739 rpc_prog_info_key rpc_prog_key;
742 unsigned int rpcvers;
743 unsigned int prog = 0;
744 unsigned int vers = 0;
745 unsigned int proc = 0;
749 unsigned int reply_state;
750 unsigned int accept_state;
751 unsigned int reject_state;
753 char *msg_type_name = NULL;
755 char *procname = NULL;
756 static char procname_static[20];
758 unsigned int vers_low;
759 unsigned int vers_high;
761 unsigned int auth_state;
763 proto_item *rpc_item=NULL;
764 proto_tree *rpc_tree = NULL;
766 proto_item *pitem=NULL;
767 proto_tree *ptree = NULL;
768 int offset_old = offset;
773 rpc_call_info rpc_call_msg;
774 rpc_proc_info_key key;
775 rpc_proc_info_value *value = NULL;
776 conversation_t* conversation;
777 static address null_address = { AT_NONE, 0, NULL };
779 dissect_function_t *dissect_function = NULL;
781 /* TCP uses record marking */
782 use_rm = (pi.ptype == PT_TCP);
784 /* the first 4 bytes are special in "record marking mode" */
786 if (!BYTES_ARE_IN_FRAME(offset,4))
788 rpc_rm = EXTRACT_UINT(pd,offset);
793 * Check to see whether this looks like an RPC call or reply.
795 if (!BYTES_ARE_IN_FRAME(offset,8)) {
796 /* Captured data in packet isn't enough to let us tell. */
800 /* both directions need at least this */
801 msg_type = EXTRACT_UINT(pd,offset+4);
806 /* check for RPC call */
807 if (!BYTES_ARE_IN_FRAME(offset,16)) {
808 /* Captured data in packet isn't enough to let us
813 /* XID can be anything, we don't check it.
814 We already have the message type.
815 Check whether an RPC version number of 2 is in the
816 location where it would be, and that an RPC program
817 number we know about is in the locaton where it would be. */
818 rpc_prog_key.prog = EXTRACT_UINT(pd,offset+12);
819 if (EXTRACT_UINT(pd,offset+8) != 2 ||
820 ((rpc_prog = g_hash_table_lookup(rpc_progs, &rpc_prog_key))
822 /* They're not, so it's probably not an RPC call. */
828 /* Check for RPC reply. A reply must match a call that
829 we've seen, and the reply must be sent to the same
830 port and address that the call came from, and must
831 come from the port to which the call was sent. (We
832 don't worry about the address to which the call was
833 sent and from which the reply was sent, because there's
834 no guarantee that the reply will come from the address
835 to which the call was sent.) */
836 conversation = find_conversation(&null_address, &pi.dst,
837 pi.ptype, pi.srcport, pi.destport);
838 if (conversation == NULL) {
839 /* We haven't seen an RPC call for that conversation,
840 so we can't check for a reply to that call. */
844 /* The XIDs of the call and reply must match. */
845 rpc_key.xid = EXTRACT_UINT(pd,offset+0);
846 rpc_key.conversation = conversation;
847 if ((rpc_call = rpc_call_lookup(&rpc_key)) == NULL) {
848 /* The XID doesn't match a call from that
849 conversation, so it's probably not an RPC reply. */
855 /* The putative message type field contains neither
856 RPC_CALL nor RPC_REPLY, so it's not an RPC call or
861 if (check_col(fd, COL_PROTOCOL))
862 col_add_str(fd, COL_PROTOCOL, "RPC");
865 rpc_item = proto_tree_add_item(tree, proto_rpc, offset, END_OF_FRAME, NULL);
867 rpc_tree = proto_item_add_subtree(rpc_item, ett_rpc);
871 if (use_rm && rpc_tree) {
872 proto_tree_add_item(rpc_tree,hf_rpc_lastfrag,
873 offset-4, 4, (rpc_rm >> 31) & 0x1);
874 proto_tree_add_item(rpc_tree,hf_rpc_fraglen,
875 offset-4, 4, rpc_rm & RPC_RM_FRAGLEN);
878 xid = EXTRACT_UINT(pd,offset+0);
880 proto_tree_add_item_format(rpc_tree,hf_rpc_xid,
881 offset+0, 4, xid, "XID: 0x%x (%u)", xid, xid);
884 msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u");
886 proto_tree_add_item(rpc_tree, hf_rpc_msgtype,
887 offset+4, 4, msg_type);
892 if (msg_type==RPC_CALL) {
893 /* we know already the proto-entry, the ETT-const,
895 proto = rpc_prog->proto;
897 progname = rpc_prog->progname;
899 rpcvers = EXTRACT_UINT(pd,offset+0);
901 proto_tree_add_item(rpc_tree,
902 hf_rpc_version, offset+0, 4, rpcvers);
905 prog = EXTRACT_UINT(pd,offset+4);
908 proto_tree_add_item_format(rpc_tree,
909 hf_rpc_program, offset+4, 4, prog,
910 "Program: %s (%u)", progname, prog);
913 if (check_col(fd, COL_PROTOCOL)) {
914 /* Set the protocol name to the underlying
916 col_add_fstr(fd, COL_PROTOCOL, "%s", progname);
919 if (!BYTES_ARE_IN_FRAME(offset+8,4))
921 vers = EXTRACT_UINT(pd,offset+8);
923 proto_tree_add_item(rpc_tree,
924 hf_rpc_programversion, offset+8, 4, vers);
927 if (!BYTES_ARE_IN_FRAME(offset+12,4))
929 proc = EXTRACT_UINT(pd,offset+12);
935 value = g_hash_table_lookup(rpc_procs,&key);
937 dissect_function = value->dissect_call;
938 procname = value->name;
941 /* happens only with strange program versions or
942 non-existing dissectors */
943 dissect_function = NULL;
944 sprintf(procname_static, "proc-%u", proc);
945 procname = procname_static;
948 proto_tree_add_item_format(rpc_tree,
949 hf_rpc_procedure, offset+12, 4, proc,
950 "Procedure: %s (%u)", procname, proc);
953 if (check_col(fd, COL_INFO)) {
954 col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
961 /* Keep track of the address and port whence the call came,
962 and the port to which the call is being sent, so that
963 we can match up calls wityh replies. (We don't worry
964 about the address to which the call was sent and from
965 which the reply was sent, because there's no
966 guarantee that the reply will come from the address
967 to which the call was sent.) */
968 conversation = find_conversation(&pi.src, &null_address,
969 pi.ptype, pi.srcport, pi.destport);
970 if (conversation == NULL) {
971 /* It's not part of any conversation - create a new one. */
972 conversation = conversation_new(&pi.src, &null_address,
973 pi.ptype, pi.srcport, pi.destport, NULL);
976 /* prepare the key data */
977 rpc_call_msg.xid = xid;
978 rpc_call_msg.conversation = conversation;
980 /* look up the request */
981 if (rpc_call_lookup(&rpc_call_msg)) {
982 /* duplicate request */
983 if (check_col(fd, COL_INFO)) {
984 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
986 proto_tree_add_item_hidden(rpc_tree,
987 hf_rpc_dup, 0,0, xid);
988 proto_tree_add_item_hidden(rpc_tree,
989 hf_rpc_call_dup, 0,0, xid);
994 /* prepare the value data */
995 rpc_call_msg.replies = 0;
996 rpc_call_msg.prog = prog;
997 rpc_call_msg.vers = vers;
998 rpc_call_msg.proc = proc;
999 rpc_call_msg.proc_info = value;
1001 rpc_call_insert(&rpc_call_msg);
1006 offset = dissect_rpc_cred(pd, offset, fd, rpc_tree);
1007 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1009 /* go to the next dissector */
1010 /* goto dissect_rpc_prog; */
1012 } /* end of RPC call */
1013 else if (msg_type == RPC_REPLY)
1015 /* we know already the type from the calling routine,
1016 and we already have "rpc_call" set above. */
1017 prog = rpc_call->prog;
1018 vers = rpc_call->vers;
1019 proc = rpc_call->proc;
1020 if (rpc_call->proc_info != NULL) {
1021 dissect_function = rpc_call->proc_info->dissect_reply;
1022 if (rpc_call->proc_info->name != NULL) {
1023 procname = rpc_call->proc_info->name;
1026 sprintf(procname_static, "proc-%u", proc);
1027 procname = procname_static;
1031 dissect_function = NULL;
1032 sprintf(procname_static, "proc-%u", proc);
1033 procname = procname_static;
1035 rpc_call->replies++;
1037 rpc_prog_key.prog = prog;
1038 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
1041 progname = "Unknown";
1044 proto = rpc_prog->proto;
1045 ett = rpc_prog->ett;
1046 progname = rpc_prog->progname;
1048 if (check_col(fd, COL_PROTOCOL)) {
1049 /* Set the protocol name to the underlying
1051 col_add_fstr(fd, COL_PROTOCOL, "%s",
1056 if (check_col(fd, COL_INFO)) {
1057 col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
1065 proto_tree_add_item_format(rpc_tree,
1066 hf_rpc_program, 0, 0, prog,
1067 "Program: %s (%u)", progname, prog);
1068 proto_tree_add_item(rpc_tree,
1069 hf_rpc_programversion, 0, 0, vers);
1070 proto_tree_add_item_format(rpc_tree,
1071 hf_rpc_procedure, 0, 0, proc,
1072 "Procedure: %s (%u)", procname, proc);
1075 if (rpc_call->replies>1) {
1076 if (check_col(fd, COL_INFO)) {
1077 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
1079 proto_tree_add_item_hidden(rpc_tree,
1080 hf_rpc_dup, 0,0, xid);
1081 proto_tree_add_item_hidden(rpc_tree,
1082 hf_rpc_reply_dup, 0,0, xid);
1087 if (!BYTES_ARE_IN_FRAME(offset,4))
1089 reply_state = EXTRACT_UINT(pd,offset+0);
1091 proto_tree_add_item(rpc_tree, hf_rpc_state_reply,
1092 offset+0, 4, reply_state);
1096 if (reply_state == MSG_ACCEPTED) {
1097 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1098 if (!BYTES_ARE_IN_FRAME(offset,4))
1100 accept_state = EXTRACT_UINT(pd,offset+0);
1102 proto_tree_add_item(rpc_tree, hf_rpc_state_accept,
1103 offset+0, 4, accept_state);
1106 switch (accept_state) {
1108 /* now goto the lower protocol */
1109 goto dissect_rpc_prog;
1112 if (!BYTES_ARE_IN_FRAME(offset,8))
1114 vers_low = EXTRACT_UINT(pd,offset+0);
1115 vers_high = EXTRACT_UINT(pd,offset+4);
1117 proto_tree_add_item(rpc_tree,
1118 hf_rpc_programversion_min,
1119 offset+0, 4, vers_low);
1120 proto_tree_add_item(rpc_tree,
1121 hf_rpc_programversion_max,
1122 offset+4, 4, vers_high);
1130 } else if (reply_state == MSG_DENIED) {
1131 if (!BYTES_ARE_IN_FRAME(offset,4))
1133 reject_state = EXTRACT_UINT(pd,offset+0);
1135 proto_tree_add_item(rpc_tree,
1136 hf_rpc_state_reject, offset+0, 4,
1141 if (reject_state==RPC_MISMATCH) {
1142 if (!BYTES_ARE_IN_FRAME(offset,8))
1144 vers_low = EXTRACT_UINT(pd,offset+0);
1145 vers_high = EXTRACT_UINT(pd,offset+4);
1147 proto_tree_add_item(rpc_tree,
1149 offset+0, 4, vers_low);
1150 proto_tree_add_item(rpc_tree,
1152 offset+4, 4, vers_high);
1155 } else if (reject_state==AUTH_ERROR) {
1156 if (!BYTES_ARE_IN_FRAME(offset,4))
1158 auth_state = EXTRACT_UINT(pd,offset+0);
1160 proto_tree_add_item(rpc_tree,
1161 hf_rpc_state_auth, offset+0, 4,
1167 } /* end of RPC reply */
1170 /* I know, goto is evil but it works as it is. */
1172 /* now we know, that RPC was shorter */
1174 proto_item_set_len(rpc_item, offset - offset_old);
1177 /* create here the program specific sub-tree */
1179 pitem = proto_tree_add_item(tree, proto, offset, END_OF_FRAME);
1181 ptree = proto_item_add_subtree(pitem, ett);
1185 proto_tree_add_item(ptree,
1186 hf_rpc_programversion, 0, 0, vers);
1187 proto_tree_add_item_format(ptree,
1188 hf_rpc_procedure, 0, 0, proc,
1189 "Procedure: %s (%u)", procname, proc);
1193 /* call a specific dissection */
1194 if (dissect_function != NULL) {
1195 offset = dissect_function(pd, offset, fd, ptree);
1198 /* dissect any remaining bytes (incomplete dissection) as pure data in
1200 dissect_data(pd, offset, fd, ptree);
1206 /* Discard any state we've saved. */
1208 rpc_init_protocol(void)
1210 memset(rpc_call_table, '\0', sizeof rpc_call_table);
1212 rpc_call_firstfree = 0;
1216 /* will be called once from register.c at startup time */
1218 proto_register_rpc(void)
1220 static hf_register_info hf[] = {
1221 { &hf_rpc_lastfrag, {
1222 "Last Fragment", "rpc.lastfrag", FT_BOOLEAN, BASE_NONE,
1223 &yesno, 0, "Last Fragment" }},
1224 { &hf_rpc_fraglen, {
1225 "Fragment Length", "rpc.fraglen", FT_UINT32, BASE_DEC,
1226 NULL, 0, "Fragment Length" }},
1228 "XID", "rpc.xid", FT_UINT32, BASE_HEX,
1230 { &hf_rpc_msgtype, {
1231 "Message Type", "rpc.msgtyp", FT_UINT32, BASE_DEC,
1232 VALS(rpc_msg_type), 0, "Message Type" }},
1233 { &hf_rpc_state_reply, {
1234 "Reply State", "rpc.replystat", FT_UINT32, BASE_DEC,
1235 VALS(rpc_reply_state), 0, "Reply State" }},
1236 { &hf_rpc_state_accept, {
1237 "Accept State", "rpc.state_accept", FT_UINT32, BASE_DEC,
1238 VALS(rpc_accept_state), 0, "Accept State" }},
1239 { &hf_rpc_state_reject, {
1240 "Reject State", "rpc.state_reject", FT_UINT32, BASE_DEC,
1241 VALS(rpc_reject_state), 0, "Reject State" }},
1242 { &hf_rpc_state_auth, {
1243 "Auth State", "rpc.state_auth", FT_UINT32, BASE_DEC,
1244 VALS(rpc_auth_state), 0, "Auth State" }},
1245 { &hf_rpc_version, {
1246 "RPC Version", "rpc.version", FT_UINT32, BASE_DEC,
1247 NULL, 0, "RPC Version" }},
1248 { &hf_rpc_version_min, {
1249 "RPC Version (Minimum)", "rpc.version.min", FT_UINT32,
1250 BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1251 { &hf_rpc_version_max, {
1252 "RPC Version (Maximum)", "rpc.version.max", FT_UINT32,
1253 BASE_DEC, NULL, 0, "RPC Version (Maximum)" }},
1254 { &hf_rpc_program, {
1255 "Program", "rpc.program", FT_UINT32, BASE_DEC,
1256 NULL, 0, "Program" }},
1257 { &hf_rpc_programversion, {
1258 "Program Version", "rpc.programversion", FT_UINT32,
1259 BASE_DEC, NULL, 0, "Program Version" }},
1260 { &hf_rpc_programversion_min, {
1261 "Program Version (Minimum)", "rpc.programversion.min", FT_UINT32,
1262 BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1263 { &hf_rpc_programversion_max, {
1264 "Program Version (Maximum)", "rpc.programversion.max", FT_UINT32,
1265 BASE_DEC, NULL, 0, "Program Version (Maximum)" }},
1266 { &hf_rpc_procedure, {
1267 "Procedure", "rpc.procedure", FT_UINT32, BASE_DEC,
1268 NULL, 0, "Procedure" }},
1269 { &hf_rpc_auth_flavor, {
1270 "Flavor", "rpc.auth.flavor", FT_UINT32, BASE_DEC,
1271 VALS(rpc_auth_flavor), 0, "Flavor" }},
1272 { &hf_rpc_auth_length, {
1273 "Length", "rpc.auth.length", FT_UINT32, BASE_DEC,
1274 NULL, 0, "Length" }},
1275 { &hf_rpc_auth_stamp, {
1276 "Stamp", "rpc.auth.stamp", FT_UINT32, BASE_HEX,
1277 NULL, 0, "Stamp" }},
1278 { &hf_rpc_auth_uid, {
1279 "UID", "rpc.auth.uid", FT_UINT32, BASE_DEC,
1281 { &hf_rpc_auth_gid, {
1282 "GID", "rpc.auth.gid", FT_UINT32, BASE_DEC,
1284 { &hf_rpc_auth_machinename, {
1285 "Machine Name", "rpc.auth.machinename", FT_STRING,
1286 BASE_DEC, NULL, 0, "Machine Name" }},
1288 "Duplicate Transaction", "rpc.dup", FT_UINT32, BASE_DEC,
1289 NULL, 0, "Duplicate Transaction" }},
1290 { &hf_rpc_call_dup, {
1291 "Duplicate Call", "rpc.call.dup", FT_UINT32, BASE_DEC,
1292 NULL, 0, "Duplicate Call" }},
1293 { &hf_rpc_reply_dup, {
1294 "Duplicate Reply", "rpc.reply.dup", FT_UINT32, BASE_DEC,
1295 NULL, 0, "Duplicate Reply" }}
1297 static gint *ett[] = {
1305 proto_rpc = proto_register_protocol("Remote Procedure Call", "rpc");
1306 proto_register_field_array(proto_rpc, hf, array_length(hf));
1307 proto_register_subtree_array(ett, array_length(ett));
1308 register_init_routine(&rpc_init_protocol);