2 * Routines for rpc dissection
3 * Copyright 1999, Uwe Girlich <Uwe.Girlich@philosys.de>
5 * $Id: packet-rpc.c,v 1.20 1999/12/02 10:20:42 girlich Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@unicom.net>
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;
120 static gint ett_rpc = -1;
121 static gint ett_rpc_string = -1;
122 static gint ett_rpc_cred = -1;
123 static gint ett_rpc_verf = -1;
124 static gint ett_rpc_gids = -1;
126 /* Hash table with info on RPC program numbers */
127 static GHashTable *rpc_progs;
129 /* Hash table with info on RPC procedure numbers */
130 static GHashTable *rpc_procs;
133 /***********************************/
134 /* Hash array with procedure names */
135 /***********************************/
139 rpc_proc_equal(gconstpointer k1, gconstpointer k2)
141 rpc_proc_info_key* key1 = (rpc_proc_info_key*) k1;
142 rpc_proc_info_key* key2 = (rpc_proc_info_key*) k2;
144 return ((key1->prog == key2->prog &&
145 key1->vers == key2->vers &&
146 key1->proc == key2->proc) ?
150 /* calculate a hash key */
152 rpc_proc_hash(gconstpointer k)
154 rpc_proc_info_key* key = (rpc_proc_info_key*) k;
156 return (key->prog ^ (key->vers<<16) ^ (key->proc<<24));
160 /* insert some entries */
162 rpc_init_proc_table(guint prog, guint vers, const vsff *proc_table)
166 for (proc = proc_table ; proc->strptr!=NULL; proc++) {
167 rpc_proc_info_key *key;
168 rpc_proc_info_value *value;
170 key = (rpc_proc_info_key *) g_malloc(sizeof(rpc_proc_info_key));
173 key->proc = proc->value;
175 value = (rpc_proc_info_value *) g_malloc(sizeof(rpc_proc_info_value));
176 value->name = proc->strptr;
177 value->dissect_call = proc->dissect_call;
178 value->dissect_reply = proc->dissect_reply;
180 g_hash_table_insert(rpc_procs,key,value);
184 /*----------------------------------------*/
185 /* end of Hash array with procedure names */
186 /*----------------------------------------*/
189 /*********************************/
190 /* Hash array with program names */
191 /*********************************/
195 rpc_prog_equal(gconstpointer k1, gconstpointer k2)
197 rpc_prog_info_key* key1 = (rpc_prog_info_key*) k1;
198 rpc_prog_info_key* key2 = (rpc_prog_info_key*) k2;
200 return ((key1->prog == key2->prog) ?
205 /* calculate a hash key */
207 rpc_prog_hash(gconstpointer k)
209 rpc_prog_info_key* key = (rpc_prog_info_key*) k;
216 rpc_init_prog(int proto, guint32 prog, int ett)
218 rpc_prog_info_key *key;
219 rpc_prog_info_value *value;
220 char *uc_progname = NULL, *lc_progname = NULL;
222 key = (rpc_prog_info_key *) g_malloc(sizeof(rpc_prog_info_key));
225 value = (rpc_prog_info_value *) g_malloc(sizeof(rpc_prog_info_value));
226 value->proto = proto;
229 lc_progname = proto_registrar_get_abbrev(proto);
233 uc_progname = strdup(lc_progname);
234 for (i=0; i<strlen(uc_progname); i++)
236 uc_progname[i] = toupper(uc_progname[i]);
239 value->progname = uc_progname;
241 g_hash_table_insert(rpc_progs,key,value);
244 /* return the name associated with a previously registered program. This
245 should probably eventually be expanded to use the rpc YP/NIS map
246 so that it can give names for programs not handled by ethereal */
247 char *rpc_prog_name(guint32 prog)
249 char *progname = NULL;
250 rpc_prog_info_key rpc_prog_key;
251 rpc_prog_info_value *rpc_prog;
253 rpc_prog_key.prog = prog;
254 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
255 progname = "Unknown";
258 progname = rpc_prog->progname;
264 /*--------------------------------------*/
265 /* end of Hash array with program names */
266 /*--------------------------------------*/
270 * Init the hash tables. It will be called from ethereal_proto_init().
271 * ethereal_proto_init() calls later proto_init(), which calls
272 * register_all_protocols().
273 * The proto_register_<some rpc program> functions use these hash tables
274 * here, so we need this order!
279 rpc_progs = g_hash_table_new(rpc_prog_hash, rpc_prog_equal);
280 rpc_procs = g_hash_table_new(rpc_proc_hash, rpc_proc_equal);
284 /* static array, first quick implementation, I'll switch over to GList soon */
285 rpc_call_info rpc_call_table[RPC_CALL_TABLE_LENGTH];
286 guint32 rpc_call_index = 0;
287 guint32 rpc_call_firstfree = 0;
290 rpc_call_insert(rpc_call_info *call)
292 /* some space left? */
293 if (rpc_call_firstfree<RPC_CALL_TABLE_LENGTH) {
294 /* some space left */
295 /* take the first free entry */
296 rpc_call_index = rpc_call_firstfree;
297 /* increase this limit */
298 rpc_call_firstfree++;
299 /* rpc_call_firstfree may now be RPC_CALL_TABLE_LENGTH */
303 /* the next entry, with wrap around */
304 rpc_call_index = (rpc_call_index+1) % rpc_call_firstfree;
307 /* put the entry in */
308 memcpy(&rpc_call_table[rpc_call_index],call,sizeof(*call));
314 rpc_call_lookup(rpc_call_info *call)
321 rpc_call_table[i].xid == call->xid &&
322 rpc_call_table[i].conversation == call->conversation
324 return &rpc_call_table[i];
326 if (rpc_call_firstfree) {
327 /* decrement by one, go to rpc_call_firstfree-1
328 at the start of the list */
329 i = (i-1+rpc_call_firstfree) % rpc_call_firstfree;
331 } while (i!=rpc_call_index);
337 rpc_roundup(unsigned int a)
339 unsigned int mod = a % 4;
340 return a + ((mod)? 4-mod : 0);
345 dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
346 char* name, char* type)
350 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
351 value = EXTRACT_UINT(pd, offset+0);
354 proto_tree_add_text(tree, offset, 4,
355 "%s: %u", name, value);
364 dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
365 char* name, char* type)
370 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
371 value_high = EXTRACT_UINT(pd, offset+0);
372 value_low = EXTRACT_UINT(pd, offset+4);
376 proto_tree_add_text(tree, offset, 8,
377 "%s: %x%08x", name, value_high, value_low);
379 proto_tree_add_text(tree, offset, 8,
380 "%s: %u", name, value_low);
389 dissect_rpc_opaque_data(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hfindex, int string_data)
391 proto_item *string_item = NULL;
392 proto_tree *string_tree = NULL;
393 int old_offset = offset;
395 int length_truncated = 0;
397 int string_truncated = 0;
398 guint32 string_length = 0;
399 guint32 string_length_full;
400 guint32 string_length_packet;
401 guint32 string_length_copy = 0;
403 int fill_truncated = 0;
404 guint32 fill_length = 0;
405 guint32 fill_length_packet = 0;
406 guint32 fill_length_copy = 0;
408 char *string_buffer = NULL;
409 char *string_buffer_print = NULL;
411 if (BYTES_ARE_IN_FRAME(offset,4)) {
412 string_length = EXTRACT_UINT(pd,offset+0);
413 string_length_full = rpc_roundup(string_length);
414 string_length_packet = pi.captured_len - (offset + 4);
415 if (string_length_packet < string_length) {
416 /* truncated string */
417 string_truncated = 1;
418 string_length_copy = string_length_packet;
421 fill_length_packet = 0;
422 fill_length_copy = 0;
425 /* full string data */
426 string_truncated = 0;
427 string_length_copy = string_length;
428 fill_length = string_length_full - string_length;
429 fill_length_packet = pi.captured_len - (offset + 4 + string_length);
430 if (fill_length_packet < fill_length) {
431 /* truncated fill bytes */
432 fill_length_copy = fill_length_packet;
436 /* full fill bytes */
437 fill_length_copy = fill_length;
441 string_buffer = (char*)g_malloc(string_length_copy +
442 (string_data ? 1 : 0));
443 memcpy(string_buffer,pd+offset+4,string_length_copy);
445 string_buffer[string_length_copy] = '\0';
447 /* calculate a nice printable string */
449 if (string_length != string_length_copy) {
451 string_buffer_print = (char*)g_malloc(string_length_copy + 1 + 12);
452 memcpy(string_buffer_print,string_buffer,string_length_copy);
453 memcpy(string_buffer_print+string_length_copy,
457 string_buffer_print = g_strdup("<DATA><TRUNCATED>");
462 string_buffer_print = g_strdup(string_buffer);
465 string_buffer_print = g_strdup("<DATA>");
470 string_buffer_print = g_strdup("<EMPTY>");
474 length_truncated = 1;
475 string_truncated = 2;
477 string_buffer = g_strdup("");
478 string_buffer_print = g_strdup("<TRUNCATED>");
482 string_item = proto_tree_add_text(tree,offset+0, END_OF_FRAME,
483 "%s: %s", proto_registrar_get_name(hfindex), string_buffer_print);
485 proto_tree_add_item_hidden(tree, hfindex, offset+4,
486 string_length_copy, string_buffer);
489 string_tree = proto_item_add_subtree(string_item, ett_rpc_string);
492 if (length_truncated) {
494 proto_tree_add_text(string_tree,
495 offset,pi.captured_len-offset,
496 "length: <TRUNCATED>");
497 offset = pi.captured_len;
500 proto_tree_add_text(string_tree,offset+0,4,
501 "length: %u", string_length);
505 proto_tree_add_text(string_tree,offset,string_length_copy,
506 "contents: %s", string_buffer_print);
507 offset += string_length_copy;
510 if (fill_truncated) {
511 proto_tree_add_text(string_tree,
512 offset,fill_length_copy,
513 "fill bytes: opaque data<TRUNCATED>");
516 proto_tree_add_text(string_tree,
517 offset,fill_length_copy,
518 "fill bytes: opaque data");
521 offset += fill_length_copy;
526 proto_item_set_len(string_item, offset - old_offset);
529 if (string_buffer != NULL) g_free (string_buffer );
530 if (string_buffer_print != NULL) g_free (string_buffer_print);
536 dissect_rpc_string(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hfindex)
538 offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, 1);
545 dissect_rpc_data(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hfindex)
547 offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, 0);
554 dissect_rpc_auth( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
560 /* both checks are made outside */
561 /* if (!BYTES_ARE_IN_FRAME(offset,8)) return; */
562 flavor = EXTRACT_UINT(pd,offset+0);
563 length = EXTRACT_UINT(pd,offset+4);
564 length_full = rpc_roundup(length);
565 /* if (!BYTES_ARE_IN_FRAME(offset+8,full_length)) return; */
568 proto_tree_add_item(tree, hf_rpc_auth_flavor, offset+0, 4,
570 proto_tree_add_item(tree, hf_rpc_auth_length, offset+4, 4,
585 proto_tree *gtree = NULL;
587 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
588 stamp = EXTRACT_UINT(pd,offset+0);
590 proto_tree_add_item(tree, hf_rpc_auth_stamp,
594 offset = dissect_rpc_string(pd,offset,fd,
595 tree,hf_rpc_auth_machinename);
597 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
598 uid = EXTRACT_UINT(pd,offset+0);
600 proto_tree_add_item(tree, hf_rpc_auth_uid,
604 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
605 gid = EXTRACT_UINT(pd,offset+0);
607 proto_tree_add_item(tree, hf_rpc_auth_gid,
611 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
612 gids_count = EXTRACT_UINT(pd,offset+0);
614 gitem = proto_tree_add_text(tree, offset, 4+gids_count*4,
616 gtree = proto_item_add_subtree(gitem, ett_rpc_gids);
619 if (!BYTES_ARE_IN_FRAME(offset,4*gids_count)) return;
620 for (gids_i = 0 ; gids_i < gids_count ; gids_i++) {
621 gids_entry = EXTRACT_UINT(pd,offset+0);
623 proto_tree_add_item(gtree, hf_rpc_auth_gid,
624 offset, 4, gids_entry);
627 /* how can I NOW change the gitem to print a list with
628 the first 16 gids? */
636 /* I have no tcpdump file with such a packet to verify the
637 info from the RFC 1050 */
646 proto_tree_add_text(tree,offset,
647 length_full, "opaque data");
653 dissect_rpc_cred( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
660 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
661 length = EXTRACT_UINT(pd,offset+4);
662 length_full = rpc_roundup(length);
663 if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
666 citem = proto_tree_add_text(tree, offset, 8+length_full,
668 ctree = proto_item_add_subtree(citem, ett_rpc_cred);
669 dissect_rpc_auth(pd, offset, fd, ctree);
671 offset += 8 + length_full;
678 dissect_rpc_verf( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
681 unsigned int length_full;
685 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
686 length = EXTRACT_UINT(pd,offset+4);
687 length_full = rpc_roundup(length);
688 if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
691 vitem = proto_tree_add_text(tree, offset, 8+length_full,
693 vtree = proto_item_add_subtree(vitem, ett_rpc_verf);
694 dissect_rpc_auth(pd, offset, fd, vtree);
696 offset += 8 + length_full;
703 dissect_rpc( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
706 rpc_call_info rpc_key;
707 rpc_call_info *rpc_call = NULL;
708 rpc_prog_info_value *rpc_prog = NULL;
709 rpc_prog_info_key rpc_prog_key;
712 unsigned int rpcvers;
713 unsigned int prog = 0;
714 unsigned int vers = 0;
715 unsigned int proc = 0;
719 unsigned int reply_state;
720 unsigned int accept_state;
721 unsigned int reject_state;
723 char *msg_type_name = NULL;
725 char *procname = NULL;
726 static char procname_static[20];
728 unsigned int vers_low;
729 unsigned int vers_high;
731 unsigned int auth_state;
733 proto_item *rpc_item=NULL;
734 proto_tree *rpc_tree = NULL;
736 proto_item *pitem=NULL;
737 proto_tree *ptree = NULL;
738 int offset_old = offset;
743 rpc_call_info rpc_call_msg;
744 rpc_proc_info_key key;
745 rpc_proc_info_value *value = NULL;
746 conversation_t* conversation;
747 static address null_address = { AT_NONE, 0, NULL };
749 dissect_function_t *dissect_function = NULL;
751 /* TCP uses record marking */
752 use_rm = (pi.ptype == PT_TCP);
754 /* the first 4 bytes are special in "record marking mode" */
756 if (!BYTES_ARE_IN_FRAME(offset,4))
758 rpc_rm = EXTRACT_UINT(pd,offset);
763 * Check to see whether this looks like an RPC call or reply.
765 if (!BYTES_ARE_IN_FRAME(offset,8)) {
766 /* Captured data in packet isn't enough to let us tell. */
770 /* both directions need at least this */
771 msg_type = EXTRACT_UINT(pd,offset+4);
776 /* check for RPC call */
777 if (!BYTES_ARE_IN_FRAME(offset,16)) {
778 /* Captured data in packet isn't enough to let us
783 /* XID can be anything, we don't check it.
784 We already have the message type.
785 Check whether an RPC version number of 2 is in the
786 location where it would be, and that an RPC program
787 number we know about is in the locaton where it would be. */
788 rpc_prog_key.prog = EXTRACT_UINT(pd,offset+12);
789 if (EXTRACT_UINT(pd,offset+8) != 2 ||
790 ((rpc_prog = g_hash_table_lookup(rpc_progs, &rpc_prog_key))
792 /* They're not, so it's probably not an RPC call. */
798 /* Check for RPC reply. A reply must match a call that
799 we've seen, and the reply must be sent to the same
800 port and address that the call came from, and must
801 come from the port to which the call was sent. (We
802 don't worry about the address to which the call was
803 sent and from which the reply was sent, because there's
804 no guarantee that the reply will come from the address
805 to which the call was sent.) */
806 conversation = find_conversation(&null_address, &pi.dst,
807 pi.ptype, pi.srcport, pi.destport);
808 if (conversation == NULL) {
809 /* We haven't seen an RPC call for that conversation,
810 so we can't check for a reply to that call. */
814 /* The XIDs of the call and reply must match. */
815 rpc_key.xid = EXTRACT_UINT(pd,offset+0);
816 rpc_key.conversation = conversation;
817 if ((rpc_call = rpc_call_lookup(&rpc_key)) == NULL) {
818 /* The XID doesn't match a call from that
819 conversation, so it's probably not an RPC reply. */
825 /* The putative message type field contains neither
826 RPC_CALL nor RPC_REPLY, so it's not an RPC call or
831 if (check_col(fd, COL_PROTOCOL))
832 col_add_str(fd, COL_PROTOCOL, "RPC");
835 rpc_item = proto_tree_add_item(tree, proto_rpc, offset, END_OF_FRAME, NULL);
837 rpc_tree = proto_item_add_subtree(rpc_item, ett_rpc);
841 if (use_rm && rpc_tree) {
842 proto_tree_add_item(rpc_tree,hf_rpc_lastfrag,
843 offset-4, 4, (rpc_rm >> 31) & 0x1);
844 proto_tree_add_item(rpc_tree,hf_rpc_fraglen,
845 offset-4, 4, rpc_rm & RPC_RM_FRAGLEN);
848 xid = EXTRACT_UINT(pd,offset+0);
850 proto_tree_add_item_format(rpc_tree,hf_rpc_xid,
851 offset+0, 4, xid, "XID: 0x%x (%u)", xid, xid);
854 msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u");
856 proto_tree_add_item(rpc_tree, hf_rpc_msgtype,
857 offset+4, 4, msg_type);
862 if (msg_type==RPC_CALL) {
863 /* we know already the proto-entry, the ETT-const,
865 proto = rpc_prog->proto;
867 progname = rpc_prog->progname;
869 rpcvers = EXTRACT_UINT(pd,offset+0);
871 proto_tree_add_item(rpc_tree,
872 hf_rpc_version, offset+0, 4, rpcvers);
875 prog = EXTRACT_UINT(pd,offset+4);
878 proto_tree_add_item_format(rpc_tree,
879 hf_rpc_program, offset+4, 4, prog,
880 "Program: %s (%u)", progname, prog);
883 if (check_col(fd, COL_PROTOCOL)) {
884 /* Set the protocol name to the underlying
886 col_add_fstr(fd, COL_PROTOCOL, "%s", progname);
889 if (!BYTES_ARE_IN_FRAME(offset+8,4))
891 vers = EXTRACT_UINT(pd,offset+8);
893 proto_tree_add_item(rpc_tree,
894 hf_rpc_programversion, offset+8, 4, vers);
897 if (!BYTES_ARE_IN_FRAME(offset+12,4))
899 proc = EXTRACT_UINT(pd,offset+12);
905 value = g_hash_table_lookup(rpc_procs,&key);
907 dissect_function = value->dissect_call;
908 procname = value->name;
911 /* happens only with strange program versions or
912 non-existing dissectors */
913 dissect_function = NULL;
914 sprintf(procname_static, "proc-%u", proc);
915 procname = procname_static;
918 proto_tree_add_item_format(rpc_tree,
919 hf_rpc_procedure, offset+12, 4, prog,
920 "Procedure: %s (%u)", procname, proc);
923 if (check_col(fd, COL_INFO)) {
924 col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
931 /* Keep track of the address and port whence the call came,
932 and the port to which the call is being sent, so that
933 we can match up calls wityh replies. (We don't worry
934 about the address to which the call was sent and from
935 which the reply was sent, because there's no
936 guarantee that the reply will come from the address
937 to which the call was sent.) */
938 conversation = find_conversation(&pi.src, &null_address,
939 pi.ptype, pi.srcport, pi.destport);
940 if (conversation == NULL) {
941 /* It's not part of any conversation - create a new one. */
942 conversation = conversation_new(&pi.src, &null_address,
943 pi.ptype, pi.srcport, pi.destport, NULL);
946 /* prepare the key data */
947 rpc_call_msg.xid = xid;
948 rpc_call_msg.conversation = conversation;
950 /* look up the request */
951 if (rpc_call_lookup(&rpc_call_msg)) {
952 /* duplicate request */
953 if (check_col(fd, COL_INFO)) {
954 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
958 /* prepare the value data */
959 rpc_call_msg.replies = 0;
960 rpc_call_msg.prog = prog;
961 rpc_call_msg.vers = vers;
962 rpc_call_msg.proc = proc;
963 rpc_call_msg.proc_info = value;
965 rpc_call_insert(&rpc_call_msg);
970 offset = dissect_rpc_cred(pd, offset, fd, rpc_tree);
971 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
973 /* go to the next dissector */
974 /* goto dissect_rpc_prog; */
976 } /* end of RPC call */
977 else if (msg_type == RPC_REPLY)
979 /* we know already the type from the calling routine,
980 and we already have "rpc_call" set above. */
981 prog = rpc_call->prog;
982 vers = rpc_call->vers;
983 proc = rpc_call->proc;
984 if (rpc_call->proc_info != NULL) {
985 dissect_function = rpc_call->proc_info->dissect_reply;
986 if (rpc_call->proc_info->name != NULL) {
987 procname = rpc_call->proc_info->name;
990 sprintf(procname_static, "proc-%u", proc);
991 procname = procname_static;
995 dissect_function = NULL;
996 sprintf(procname_static, "proc-%u", proc);
997 procname = procname_static;
1001 rpc_prog_key.prog = prog;
1002 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
1005 progname = "Unknown";
1008 proto = rpc_prog->proto;
1009 ett = rpc_prog->ett;
1010 progname = rpc_prog->progname;
1012 if (check_col(fd, COL_PROTOCOL)) {
1013 /* Set the protocol name to the underlying
1015 col_add_fstr(fd, COL_PROTOCOL, "%s",
1020 if (check_col(fd, COL_INFO)) {
1021 col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
1029 proto_tree_add_item_format(rpc_tree,
1030 hf_rpc_program, 0, 0, prog,
1031 "Program: %s (%u)", progname, prog);
1032 proto_tree_add_item(rpc_tree,
1033 hf_rpc_programversion, 0, 0, vers);
1034 proto_tree_add_item_format(rpc_tree,
1035 hf_rpc_procedure, 0, 0, prog,
1036 "Procedure: %s (%u)", procname, proc);
1039 if (rpc_call->replies>1) {
1040 if (check_col(fd, COL_INFO)) {
1041 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
1045 if (!BYTES_ARE_IN_FRAME(offset,4))
1047 reply_state = EXTRACT_UINT(pd,offset+0);
1049 proto_tree_add_item(rpc_tree, hf_rpc_state_reply,
1050 offset+0, 4, reply_state);
1054 if (reply_state == MSG_ACCEPTED) {
1055 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1056 if (!BYTES_ARE_IN_FRAME(offset,4))
1058 accept_state = EXTRACT_UINT(pd,offset+0);
1060 proto_tree_add_item(rpc_tree, hf_rpc_state_accept,
1061 offset+0, 4, accept_state);
1064 switch (accept_state) {
1066 /* now goto the lower protocol */
1067 goto dissect_rpc_prog;
1070 if (!BYTES_ARE_IN_FRAME(offset,8))
1072 vers_low = EXTRACT_UINT(pd,offset+0);
1073 vers_high = EXTRACT_UINT(pd,offset+4);
1075 proto_tree_add_item(rpc_tree,
1076 hf_rpc_programversion_min,
1077 offset+0, 4, vers_low);
1078 proto_tree_add_item(rpc_tree,
1079 hf_rpc_programversion_max,
1080 offset+4, 4, vers_high);
1088 } else if (reply_state == MSG_DENIED) {
1089 if (!BYTES_ARE_IN_FRAME(offset,4))
1091 reject_state = EXTRACT_UINT(pd,offset+0);
1093 proto_tree_add_item(rpc_tree,
1094 hf_rpc_state_reject, offset+0, 4,
1099 if (reject_state==RPC_MISMATCH) {
1100 if (!BYTES_ARE_IN_FRAME(offset,8))
1102 vers_low = EXTRACT_UINT(pd,offset+0);
1103 vers_high = EXTRACT_UINT(pd,offset+4);
1105 proto_tree_add_item(rpc_tree,
1107 offset+0, 4, vers_low);
1108 proto_tree_add_item(rpc_tree,
1110 offset+4, 4, vers_high);
1113 } else if (reject_state==AUTH_ERROR) {
1114 if (!BYTES_ARE_IN_FRAME(offset,4))
1116 auth_state = EXTRACT_UINT(pd,offset+0);
1118 proto_tree_add_item(rpc_tree,
1119 hf_rpc_state_auth, offset+0, 4,
1125 } /* end of RPC reply */
1128 /* I know, goto is evil but it works as it is. */
1130 /* now we know, that RPC was shorter */
1132 proto_item_set_len(rpc_item, offset - offset_old);
1135 /* create here the program specific sub-tree */
1137 pitem = proto_tree_add_item(tree, proto, offset, END_OF_FRAME);
1139 ptree = proto_item_add_subtree(pitem, ett);
1143 proto_tree_add_item(ptree,
1144 hf_rpc_programversion, 0, 0, vers);
1145 proto_tree_add_item_format(ptree,
1146 hf_rpc_procedure, 0, 0, prog,
1147 "Procedure: %s (%u)", procname, proc);
1151 /* call a specific dissection */
1152 if (dissect_function != NULL) {
1153 offset = dissect_function(pd, offset, fd, ptree);
1156 /* dissect any remaining bytes (incomplete dissection) as pure data in
1158 dissect_data(pd, offset, fd, ptree);
1164 /* Discard any state we've saved. */
1166 rpc_init_protocol(void)
1168 memset(rpc_call_table, '\0', sizeof rpc_call_table);
1170 rpc_call_firstfree = 0;
1174 /* will be called once from register.c at startup time */
1176 proto_register_rpc(void)
1178 static hf_register_info hf[] = {
1179 { &hf_rpc_lastfrag, {
1180 "Last Fragment", "rpc.lastfrag", FT_BOOLEAN, BASE_NONE,
1181 &yesno, 0, "Last Fragment" }},
1182 { &hf_rpc_fraglen, {
1183 "Fragment Length", "rpc.fraglen", FT_UINT32, BASE_DEC,
1184 NULL, 0, "Fragment Length" }},
1186 "XID", "rpc.xid", FT_UINT32, BASE_HEX,
1188 { &hf_rpc_msgtype, {
1189 "Message Type", "rpc.msgtyp", FT_UINT32, BASE_DEC,
1190 VALS(rpc_msg_type), 0, "Message Type" }},
1191 { &hf_rpc_state_reply, {
1192 "Reply State", "rpc.replystat", FT_UINT32, BASE_DEC,
1193 VALS(rpc_reply_state), 0, "Reply State" }},
1194 { &hf_rpc_state_accept, {
1195 "Accept State", "rpc.state_accept", FT_UINT32, BASE_DEC,
1196 VALS(rpc_accept_state), 0, "Accept State" }},
1197 { &hf_rpc_state_reject, {
1198 "Reject State", "rpc.state_reject", FT_UINT32, BASE_DEC,
1199 VALS(rpc_reject_state), 0, "Reject State" }},
1200 { &hf_rpc_state_auth, {
1201 "Auth State", "rpc.state_auth", FT_UINT32, BASE_DEC,
1202 VALS(rpc_auth_state), 0, "Auth State" }},
1203 { &hf_rpc_version, {
1204 "RPC Version", "rpc.version", FT_UINT32, BASE_DEC,
1205 NULL, 0, "RPC Version" }},
1206 { &hf_rpc_version_min, {
1207 "RPC Version (Minimum)", "rpc.version.min", FT_UINT32,
1208 BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1209 { &hf_rpc_version_max, {
1210 "RPC Version (Maximum)", "rpc.version.max", FT_UINT32,
1211 BASE_DEC, NULL, 0, "RPC Version (Maximum)" }},
1212 { &hf_rpc_program, {
1213 "Program", "rpc.program", FT_UINT32, BASE_DEC,
1214 NULL, 0, "Program" }},
1215 { &hf_rpc_programversion, {
1216 "Program Version", "rpc.programversion", FT_UINT32,
1217 BASE_DEC, NULL, 0, "Program Version" }},
1218 { &hf_rpc_programversion_min, {
1219 "Program Version (Minimum)", "rpc.programversion.min", FT_UINT32,
1220 BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1221 { &hf_rpc_programversion_max, {
1222 "Program Version (Maximum)", "rpc.programversion.max", FT_UINT32,
1223 BASE_DEC, NULL, 0, "Program Version (Maximum)" }},
1224 { &hf_rpc_procedure, {
1225 "Procedure", "rpc.procedure", FT_UINT32, BASE_DEC,
1226 NULL, 0, "Procedure" }},
1227 { &hf_rpc_auth_flavor, {
1228 "Flavor", "rpc.auth.flavor", FT_UINT32, BASE_DEC,
1229 VALS(rpc_auth_flavor), 0, "Flavor" }},
1230 { &hf_rpc_auth_length, {
1231 "Length", "rpc.auth.length", FT_UINT32, BASE_DEC,
1232 NULL, 0, "Length" }},
1233 { &hf_rpc_auth_stamp, {
1234 "Stamp", "rpc.auth.stamp", FT_UINT32, BASE_HEX,
1235 NULL, 0, "Stamp" }},
1236 { &hf_rpc_auth_uid, {
1237 "UID", "rpc.auth.uid", FT_UINT32, BASE_DEC,
1239 { &hf_rpc_auth_gid, {
1240 "GID", "rpc.auth.gid", FT_UINT32, BASE_DEC,
1242 { &hf_rpc_auth_machinename, {
1243 "Machine Name", "rpc.auth.machinename", FT_STRING,
1244 BASE_DEC, NULL, 0, "Machine Name" }},
1246 static gint *ett[] = {
1254 proto_rpc = proto_register_protocol("Remote Procedure Call", "rpc");
1255 proto_register_field_array(proto_rpc, hf, array_length(hf));
1256 proto_register_subtree_array(ett, array_length(ett));
1257 register_init_routine(&rpc_init_protocol);