2 * Routines for rpc dissection
3 * Copyright 1999, Uwe Girlich <Uwe.Girlich@philosys.de>
5 * $Id: packet-rpc.c,v 1.29 2000/04/04 06:46:27 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;
122 static int hf_rpc_value_follows = -1;
124 static gint ett_rpc = -1;
125 static gint ett_rpc_string = -1;
126 static gint ett_rpc_cred = -1;
127 static gint ett_rpc_verf = -1;
128 static gint ett_rpc_gids = -1;
130 /* Hash table with info on RPC program numbers */
131 static GHashTable *rpc_progs;
133 /* Hash table with info on RPC procedure numbers */
134 static GHashTable *rpc_procs;
137 /***********************************/
138 /* Hash array with procedure names */
139 /***********************************/
143 rpc_proc_equal(gconstpointer k1, gconstpointer k2)
145 rpc_proc_info_key* key1 = (rpc_proc_info_key*) k1;
146 rpc_proc_info_key* key2 = (rpc_proc_info_key*) k2;
148 return ((key1->prog == key2->prog &&
149 key1->vers == key2->vers &&
150 key1->proc == key2->proc) ?
154 /* calculate a hash key */
156 rpc_proc_hash(gconstpointer k)
158 rpc_proc_info_key* key = (rpc_proc_info_key*) k;
160 return (key->prog ^ (key->vers<<16) ^ (key->proc<<24));
164 /* insert some entries */
166 rpc_init_proc_table(guint prog, guint vers, const vsff *proc_table)
170 for (proc = proc_table ; proc->strptr!=NULL; proc++) {
171 rpc_proc_info_key *key;
172 rpc_proc_info_value *value;
174 key = (rpc_proc_info_key *) g_malloc(sizeof(rpc_proc_info_key));
177 key->proc = proc->value;
179 value = (rpc_proc_info_value *) g_malloc(sizeof(rpc_proc_info_value));
180 value->name = proc->strptr;
181 value->dissect_call = proc->dissect_call;
182 value->dissect_reply = proc->dissect_reply;
184 g_hash_table_insert(rpc_procs,key,value);
188 /*----------------------------------------*/
189 /* end of Hash array with procedure names */
190 /*----------------------------------------*/
193 /*********************************/
194 /* Hash array with program names */
195 /*********************************/
199 rpc_prog_equal(gconstpointer k1, gconstpointer k2)
201 rpc_prog_info_key* key1 = (rpc_prog_info_key*) k1;
202 rpc_prog_info_key* key2 = (rpc_prog_info_key*) k2;
204 return ((key1->prog == key2->prog) ?
209 /* calculate a hash key */
211 rpc_prog_hash(gconstpointer k)
213 rpc_prog_info_key* key = (rpc_prog_info_key*) k;
220 rpc_init_prog(int proto, guint32 prog, int ett)
222 rpc_prog_info_key *key;
223 rpc_prog_info_value *value;
224 char *uc_progname = NULL, *lc_progname = NULL;
226 key = (rpc_prog_info_key *) g_malloc(sizeof(rpc_prog_info_key));
229 value = (rpc_prog_info_value *) g_malloc(sizeof(rpc_prog_info_value));
230 value->proto = proto;
233 lc_progname = proto_registrar_get_abbrev(proto);
237 uc_progname = strdup(lc_progname);
238 for (i=0; i<strlen(uc_progname); i++)
240 uc_progname[i] = toupper(uc_progname[i]);
243 value->progname = uc_progname;
245 g_hash_table_insert(rpc_progs,key,value);
248 /* return the name associated with a previously registered program. This
249 should probably eventually be expanded to use the rpc YP/NIS map
250 so that it can give names for programs not handled by ethereal */
251 char *rpc_prog_name(guint32 prog)
253 char *progname = NULL;
254 rpc_prog_info_key rpc_prog_key;
255 rpc_prog_info_value *rpc_prog;
257 rpc_prog_key.prog = prog;
258 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
259 progname = "Unknown";
262 progname = rpc_prog->progname;
268 /*--------------------------------------*/
269 /* end of Hash array with program names */
270 /*--------------------------------------*/
272 /* static array, first quick implementation, I'll switch over to GList soon */
273 rpc_call_info rpc_call_table[RPC_CALL_TABLE_LENGTH];
274 guint32 rpc_call_index = 0;
275 guint32 rpc_call_firstfree = 0;
278 rpc_call_insert(rpc_call_info *call)
280 /* some space left? */
281 if (rpc_call_firstfree<RPC_CALL_TABLE_LENGTH) {
282 /* some space left */
283 /* take the first free entry */
284 rpc_call_index = rpc_call_firstfree;
285 /* increase this limit */
286 rpc_call_firstfree++;
287 /* rpc_call_firstfree may now be RPC_CALL_TABLE_LENGTH */
291 /* the next entry, with wrap around */
292 rpc_call_index = (rpc_call_index+1) % rpc_call_firstfree;
295 /* put the entry in */
296 memcpy(&rpc_call_table[rpc_call_index],call,sizeof(*call));
302 rpc_call_lookup(rpc_call_info *call)
309 rpc_call_table[i].xid == call->xid &&
310 rpc_call_table[i].conversation == call->conversation
312 return &rpc_call_table[i];
314 if (rpc_call_firstfree) {
315 /* decrement by one, go to rpc_call_firstfree-1
316 at the start of the list */
317 i = (i-1+rpc_call_firstfree) % rpc_call_firstfree;
319 } while (i!=rpc_call_index);
325 rpc_roundup(unsigned int a)
327 unsigned int mod = a % 4;
328 return a + ((mod)? 4-mod : 0);
333 dissect_rpc_bool(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
338 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
339 value = EXTRACT_UINT(pd, offset+0);
341 proto_tree_add_item(tree, hfindex, offset, 4, value);
349 dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
350 char* name, char* type)
354 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
355 value = EXTRACT_UINT(pd, offset+0);
358 proto_tree_add_text(tree, offset, 4,
359 "%s: %u", name, value);
368 dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
369 char* name, char* type)
374 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
375 value_high = EXTRACT_UINT(pd, offset+0);
376 value_low = EXTRACT_UINT(pd, offset+4);
380 proto_tree_add_text(tree, offset, 8,
381 "%s: 0x%x%08x", name, value_high, value_low);
383 proto_tree_add_text(tree, offset, 8,
384 "%s: %u", name, value_low);
393 dissect_rpc_opaque_data(const u_char *pd, int offset, frame_data *fd,
394 proto_tree *tree, int hfindex, gboolean string_data,
395 char **string_buffer_ret)
397 proto_item *string_item = NULL;
398 proto_tree *string_tree = NULL;
399 int old_offset = offset;
401 int length_truncated = 0;
403 int string_truncated = 0;
404 guint32 string_length = 0;
405 guint32 string_length_full;
406 guint32 string_length_packet;
407 guint32 string_length_copy = 0;
409 int fill_truncated = 0;
410 guint32 fill_length = 0;
411 guint32 fill_length_packet = 0;
412 guint32 fill_length_copy = 0;
414 char *string_buffer = NULL;
415 char *string_buffer_print = NULL;
417 if (BYTES_ARE_IN_FRAME(offset,4)) {
418 string_length = EXTRACT_UINT(pd,offset+0);
419 string_length_full = rpc_roundup(string_length);
420 string_length_packet = pi.captured_len - (offset + 4);
421 if (string_length_packet < string_length) {
422 /* truncated string */
423 string_truncated = 1;
424 string_length_copy = string_length_packet;
427 fill_length_packet = 0;
428 fill_length_copy = 0;
431 /* full string data */
432 string_truncated = 0;
433 string_length_copy = string_length;
434 fill_length = string_length_full - string_length;
435 fill_length_packet = pi.captured_len - (offset + 4 + string_length);
436 if (fill_length_packet < fill_length) {
437 /* truncated fill bytes */
438 fill_length_copy = fill_length_packet;
442 /* full fill bytes */
443 fill_length_copy = fill_length;
447 string_buffer = (char*)g_malloc(string_length_copy +
448 (string_data ? 1 : 0));
449 memcpy(string_buffer,pd+offset+4,string_length_copy);
451 string_buffer[string_length_copy] = '\0';
453 /* calculate a nice printable string */
455 if (string_length != string_length_copy) {
457 /* alloc maximum data area */
458 string_buffer_print = (char*)g_malloc(string_length_copy + 12 + 1);
459 /* copy over the data */
460 memcpy(string_buffer_print,string_buffer,string_length_copy);
461 /* append a 0 byte for sure printing */
462 string_buffer_print[string_length_copy] = '\0';
463 /* append <TRUNCATED> */
464 /* This way, we get the TRUNCATED even
465 in the case of totally wrong packets,
466 where \0 are inside the string.
467 TRUNCATED will appear at the
468 first \0 or at the end (where we
469 put the securing \0).
471 strcat(string_buffer_print,"<TRUNCATED>");
474 string_buffer_print = g_strdup("<DATA><TRUNCATED>");
479 string_buffer_print = g_strdup(string_buffer);
482 string_buffer_print = g_strdup("<DATA>");
487 string_buffer_print = g_strdup("<EMPTY>");
491 length_truncated = 1;
492 string_truncated = 2;
494 string_buffer = g_strdup("");
495 string_buffer_print = g_strdup("<TRUNCATED>");
499 string_item = proto_tree_add_text(tree,offset+0, END_OF_FRAME,
500 "%s: %s", proto_registrar_get_name(hfindex), string_buffer_print);
502 proto_tree_add_item_hidden(tree, hfindex, offset+4,
503 string_length_copy, string_buffer);
506 string_tree = proto_item_add_subtree(string_item, ett_rpc_string);
509 if (length_truncated) {
511 proto_tree_add_text(string_tree,
512 offset,pi.captured_len-offset,
513 "length: <TRUNCATED>");
514 offset = pi.captured_len;
517 proto_tree_add_text(string_tree,offset+0,4,
518 "length: %u", string_length);
522 proto_tree_add_text(string_tree,offset,string_length_copy,
523 "contents: %s", string_buffer_print);
524 offset += string_length_copy;
527 if (fill_truncated) {
528 proto_tree_add_text(string_tree,
529 offset,fill_length_copy,
530 "fill bytes: opaque data<TRUNCATED>");
533 proto_tree_add_text(string_tree,
534 offset,fill_length_copy,
535 "fill bytes: opaque data");
538 offset += fill_length_copy;
543 proto_item_set_len(string_item, offset - old_offset);
546 if (string_buffer != NULL) g_free (string_buffer );
547 if (string_buffer_print != NULL) {
548 if (string_buffer_ret != NULL)
549 *string_buffer_ret = string_buffer_print;
551 g_free (string_buffer_print);
558 dissect_rpc_string(const u_char *pd, int offset, frame_data *fd,
559 proto_tree *tree, int hfindex, char **string_buffer_ret)
561 offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, TRUE,
569 dissect_rpc_data(const u_char *pd, int offset, frame_data *fd,
570 proto_tree *tree, int hfindex)
572 offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, FALSE,
580 dissect_rpc_list(const u_char *pd, int offset, frame_data *fd,
581 proto_tree *tree, dissect_function_t *rpc_list_dissector)
583 guint32 value_follows;
586 if (!BYTES_ARE_IN_FRAME(offset,4)) break;
587 value_follows = EXTRACT_UINT(pd, offset+0);
588 proto_tree_add_item(tree,hf_rpc_value_follows,
589 offset+0, 4, value_follows);
591 if (value_follows == 1) {
592 offset = rpc_list_dissector(pd, offset, fd, tree);
604 dissect_rpc_auth( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
610 /* both checks are made outside */
611 /* if (!BYTES_ARE_IN_FRAME(offset,8)) return; */
612 flavor = EXTRACT_UINT(pd,offset+0);
613 length = EXTRACT_UINT(pd,offset+4);
614 length_full = rpc_roundup(length);
615 /* if (!BYTES_ARE_IN_FRAME(offset+8,full_length)) return; */
618 proto_tree_add_item(tree, hf_rpc_auth_flavor, offset+0, 4,
620 proto_tree_add_item(tree, hf_rpc_auth_length, offset+4, 4,
635 proto_tree *gtree = NULL;
637 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
638 stamp = EXTRACT_UINT(pd,offset+0);
640 proto_tree_add_item(tree, hf_rpc_auth_stamp,
644 offset = dissect_rpc_string(pd,offset,fd,
645 tree,hf_rpc_auth_machinename,NULL);
647 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
648 uid = EXTRACT_UINT(pd,offset+0);
650 proto_tree_add_item(tree, hf_rpc_auth_uid,
654 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
655 gid = EXTRACT_UINT(pd,offset+0);
657 proto_tree_add_item(tree, hf_rpc_auth_gid,
661 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
662 gids_count = EXTRACT_UINT(pd,offset+0);
664 gitem = proto_tree_add_text(tree, offset, 4+gids_count*4,
666 gtree = proto_item_add_subtree(gitem, ett_rpc_gids);
669 if (!BYTES_ARE_IN_FRAME(offset,4*gids_count)) return;
670 for (gids_i = 0 ; gids_i < gids_count ; gids_i++) {
671 gids_entry = EXTRACT_UINT(pd,offset+0);
673 proto_tree_add_item(gtree, hf_rpc_auth_gid,
674 offset, 4, gids_entry);
677 /* how can I NOW change the gitem to print a list with
678 the first 16 gids? */
686 /* I have no tcpdump file with such a packet to verify the
687 info from the RFC 1050 */
696 proto_tree_add_text(tree,offset,
697 length_full, "opaque data");
703 dissect_rpc_cred( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
710 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
711 length = EXTRACT_UINT(pd,offset+4);
712 length_full = rpc_roundup(length);
713 if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
716 citem = proto_tree_add_text(tree, offset, 8+length_full,
718 ctree = proto_item_add_subtree(citem, ett_rpc_cred);
719 dissect_rpc_auth(pd, offset, fd, ctree);
721 offset += 8 + length_full;
728 dissect_rpc_verf( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
731 unsigned int length_full;
735 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
736 length = EXTRACT_UINT(pd,offset+4);
737 length_full = rpc_roundup(length);
738 if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
741 vitem = proto_tree_add_text(tree, offset, 8+length_full,
743 vtree = proto_item_add_subtree(vitem, ett_rpc_verf);
744 dissect_rpc_auth(pd, offset, fd, vtree);
746 offset += 8 + length_full;
753 dissect_rpc( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
756 rpc_call_info rpc_key;
757 rpc_call_info *rpc_call = NULL;
758 rpc_prog_info_value *rpc_prog = NULL;
759 rpc_prog_info_key rpc_prog_key;
762 unsigned int rpcvers;
763 unsigned int prog = 0;
764 unsigned int vers = 0;
765 unsigned int proc = 0;
769 unsigned int reply_state;
770 unsigned int accept_state;
771 unsigned int reject_state;
773 char *msg_type_name = NULL;
775 char *procname = NULL;
776 static char procname_static[20];
778 unsigned int vers_low;
779 unsigned int vers_high;
781 unsigned int auth_state;
783 proto_item *rpc_item=NULL;
784 proto_tree *rpc_tree = NULL;
786 proto_item *pitem=NULL;
787 proto_tree *ptree = NULL;
788 int offset_old = offset;
793 rpc_call_info rpc_call_msg;
794 rpc_proc_info_key key;
795 rpc_proc_info_value *value = NULL;
796 conversation_t* conversation;
797 static address null_address = { AT_NONE, 0, NULL };
799 dissect_function_t *dissect_function = NULL;
801 /* TCP uses record marking */
802 use_rm = (pi.ptype == PT_TCP);
804 /* the first 4 bytes are special in "record marking mode" */
806 if (!BYTES_ARE_IN_FRAME(offset,4))
808 rpc_rm = EXTRACT_UINT(pd,offset);
813 * Check to see whether this looks like an RPC call or reply.
815 if (!BYTES_ARE_IN_FRAME(offset,8)) {
816 /* Captured data in packet isn't enough to let us tell. */
820 /* both directions need at least this */
821 msg_type = EXTRACT_UINT(pd,offset+4);
826 /* check for RPC call */
827 if (!BYTES_ARE_IN_FRAME(offset,16)) {
828 /* Captured data in packet isn't enough to let us
833 /* XID can be anything, we don't check it.
834 We already have the message type.
835 Check whether an RPC version number of 2 is in the
836 location where it would be, and that an RPC program
837 number we know about is in the locaton where it would be. */
838 rpc_prog_key.prog = EXTRACT_UINT(pd,offset+12);
839 if (EXTRACT_UINT(pd,offset+8) != 2 ||
840 ((rpc_prog = g_hash_table_lookup(rpc_progs, &rpc_prog_key))
842 /* They're not, so it's probably not an RPC call. */
848 /* Check for RPC reply. A reply must match a call that
849 we've seen, and the reply must be sent to the same
850 port and address that the call came from, and must
851 come from the port to which the call was sent. (We
852 don't worry about the address to which the call was
853 sent and from which the reply was sent, because there's
854 no guarantee that the reply will come from the address
855 to which the call was sent.) */
856 conversation = find_conversation(&null_address, &pi.dst,
857 pi.ptype, pi.srcport, pi.destport);
858 if (conversation == NULL) {
859 /* We haven't seen an RPC call for that conversation,
860 so we can't check for a reply to that call. */
864 /* The XIDs of the call and reply must match. */
865 rpc_key.xid = EXTRACT_UINT(pd,offset+0);
866 rpc_key.conversation = conversation;
867 if ((rpc_call = rpc_call_lookup(&rpc_key)) == NULL) {
868 /* The XID doesn't match a call from that
869 conversation, so it's probably not an RPC reply. */
875 /* The putative message type field contains neither
876 RPC_CALL nor RPC_REPLY, so it's not an RPC call or
881 if (check_col(fd, COL_PROTOCOL))
882 col_add_str(fd, COL_PROTOCOL, "RPC");
885 rpc_item = proto_tree_add_item(tree, proto_rpc, offset, END_OF_FRAME, NULL);
887 rpc_tree = proto_item_add_subtree(rpc_item, ett_rpc);
891 if (use_rm && rpc_tree) {
892 proto_tree_add_item(rpc_tree,hf_rpc_lastfrag,
893 offset-4, 4, (rpc_rm >> 31) & 0x1);
894 proto_tree_add_item(rpc_tree,hf_rpc_fraglen,
895 offset-4, 4, rpc_rm & RPC_RM_FRAGLEN);
898 xid = EXTRACT_UINT(pd,offset+0);
900 proto_tree_add_uint_format(rpc_tree,hf_rpc_xid,
901 offset+0, 4, xid, "XID: 0x%x (%u)", xid, xid);
904 msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u");
906 proto_tree_add_item(rpc_tree, hf_rpc_msgtype,
907 offset+4, 4, msg_type);
912 if (msg_type==RPC_CALL) {
913 /* we know already the proto-entry, the ETT-const,
915 proto = rpc_prog->proto;
917 progname = rpc_prog->progname;
919 rpcvers = EXTRACT_UINT(pd,offset+0);
921 proto_tree_add_item(rpc_tree,
922 hf_rpc_version, offset+0, 4, rpcvers);
925 prog = EXTRACT_UINT(pd,offset+4);
928 proto_tree_add_uint_format(rpc_tree,
929 hf_rpc_program, offset+4, 4, prog,
930 "Program: %s (%u)", progname, prog);
933 if (check_col(fd, COL_PROTOCOL)) {
934 /* Set the protocol name to the underlying
936 col_add_fstr(fd, COL_PROTOCOL, "%s", progname);
939 if (!BYTES_ARE_IN_FRAME(offset+8,4))
941 vers = EXTRACT_UINT(pd,offset+8);
943 proto_tree_add_item(rpc_tree,
944 hf_rpc_programversion, offset+8, 4, vers);
947 if (!BYTES_ARE_IN_FRAME(offset+12,4))
949 proc = EXTRACT_UINT(pd,offset+12);
955 value = g_hash_table_lookup(rpc_procs,&key);
957 dissect_function = value->dissect_call;
958 procname = value->name;
961 /* happens only with strange program versions or
962 non-existing dissectors */
963 dissect_function = NULL;
964 sprintf(procname_static, "proc-%u", proc);
965 procname = procname_static;
968 proto_tree_add_uint_format(rpc_tree,
969 hf_rpc_procedure, offset+12, 4, proc,
970 "Procedure: %s (%u)", procname, proc);
973 if (check_col(fd, COL_INFO)) {
974 col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
981 /* Keep track of the address and port whence the call came,
982 and the port to which the call is being sent, so that
983 we can match up calls wityh replies. (We don't worry
984 about the address to which the call was sent and from
985 which the reply was sent, because there's no
986 guarantee that the reply will come from the address
987 to which the call was sent.) */
988 conversation = find_conversation(&pi.src, &null_address,
989 pi.ptype, pi.srcport, pi.destport);
990 if (conversation == NULL) {
991 /* It's not part of any conversation - create a new one. */
992 conversation = conversation_new(&pi.src, &null_address,
993 pi.ptype, pi.srcport, pi.destport, NULL);
996 /* prepare the key data */
997 rpc_call_msg.xid = xid;
998 rpc_call_msg.conversation = conversation;
1000 /* look up the request */
1001 if (rpc_call_lookup(&rpc_call_msg)) {
1002 /* duplicate request */
1003 if (check_col(fd, COL_INFO)) {
1004 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
1006 proto_tree_add_item_hidden(rpc_tree,
1007 hf_rpc_dup, 0,0, xid);
1008 proto_tree_add_item_hidden(rpc_tree,
1009 hf_rpc_call_dup, 0,0, xid);
1014 /* prepare the value data */
1015 rpc_call_msg.replies = 0;
1016 rpc_call_msg.prog = prog;
1017 rpc_call_msg.vers = vers;
1018 rpc_call_msg.proc = proc;
1019 rpc_call_msg.proc_info = value;
1021 rpc_call_insert(&rpc_call_msg);
1026 offset = dissect_rpc_cred(pd, offset, fd, rpc_tree);
1027 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1029 /* go to the next dissector */
1030 /* goto dissect_rpc_prog; */
1032 } /* end of RPC call */
1033 else if (msg_type == RPC_REPLY)
1035 /* we know already the type from the calling routine,
1036 and we already have "rpc_call" set above. */
1037 prog = rpc_call->prog;
1038 vers = rpc_call->vers;
1039 proc = rpc_call->proc;
1040 if (rpc_call->proc_info != NULL) {
1041 dissect_function = rpc_call->proc_info->dissect_reply;
1042 if (rpc_call->proc_info->name != NULL) {
1043 procname = rpc_call->proc_info->name;
1046 sprintf(procname_static, "proc-%u", proc);
1047 procname = procname_static;
1051 dissect_function = NULL;
1052 sprintf(procname_static, "proc-%u", proc);
1053 procname = procname_static;
1055 rpc_call->replies++;
1057 rpc_prog_key.prog = prog;
1058 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
1061 progname = "Unknown";
1064 proto = rpc_prog->proto;
1065 ett = rpc_prog->ett;
1066 progname = rpc_prog->progname;
1068 if (check_col(fd, COL_PROTOCOL)) {
1069 /* Set the protocol name to the underlying
1071 col_add_fstr(fd, COL_PROTOCOL, "%s",
1076 if (check_col(fd, COL_INFO)) {
1077 col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
1085 proto_tree_add_uint_format(rpc_tree,
1086 hf_rpc_program, 0, 0, prog,
1087 "Program: %s (%u)", progname, prog);
1088 proto_tree_add_item(rpc_tree,
1089 hf_rpc_programversion, 0, 0, vers);
1090 proto_tree_add_uint_format(rpc_tree,
1091 hf_rpc_procedure, 0, 0, proc,
1092 "Procedure: %s (%u)", procname, proc);
1095 if (rpc_call->replies>1) {
1096 if (check_col(fd, COL_INFO)) {
1097 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
1099 proto_tree_add_item_hidden(rpc_tree,
1100 hf_rpc_dup, 0,0, xid);
1101 proto_tree_add_item_hidden(rpc_tree,
1102 hf_rpc_reply_dup, 0,0, xid);
1107 if (!BYTES_ARE_IN_FRAME(offset,4))
1109 reply_state = EXTRACT_UINT(pd,offset+0);
1111 proto_tree_add_item(rpc_tree, hf_rpc_state_reply,
1112 offset+0, 4, reply_state);
1116 if (reply_state == MSG_ACCEPTED) {
1117 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1118 if (!BYTES_ARE_IN_FRAME(offset,4))
1120 accept_state = EXTRACT_UINT(pd,offset+0);
1122 proto_tree_add_item(rpc_tree, hf_rpc_state_accept,
1123 offset+0, 4, accept_state);
1126 switch (accept_state) {
1128 /* now goto the lower protocol */
1129 goto dissect_rpc_prog;
1132 if (!BYTES_ARE_IN_FRAME(offset,8))
1134 vers_low = EXTRACT_UINT(pd,offset+0);
1135 vers_high = EXTRACT_UINT(pd,offset+4);
1137 proto_tree_add_item(rpc_tree,
1138 hf_rpc_programversion_min,
1139 offset+0, 4, vers_low);
1140 proto_tree_add_item(rpc_tree,
1141 hf_rpc_programversion_max,
1142 offset+4, 4, vers_high);
1150 } else if (reply_state == MSG_DENIED) {
1151 if (!BYTES_ARE_IN_FRAME(offset,4))
1153 reject_state = EXTRACT_UINT(pd,offset+0);
1155 proto_tree_add_item(rpc_tree,
1156 hf_rpc_state_reject, offset+0, 4,
1161 if (reject_state==RPC_MISMATCH) {
1162 if (!BYTES_ARE_IN_FRAME(offset,8))
1164 vers_low = EXTRACT_UINT(pd,offset+0);
1165 vers_high = EXTRACT_UINT(pd,offset+4);
1167 proto_tree_add_item(rpc_tree,
1169 offset+0, 4, vers_low);
1170 proto_tree_add_item(rpc_tree,
1172 offset+4, 4, vers_high);
1175 } else if (reject_state==AUTH_ERROR) {
1176 if (!BYTES_ARE_IN_FRAME(offset,4))
1178 auth_state = EXTRACT_UINT(pd,offset+0);
1180 proto_tree_add_item(rpc_tree,
1181 hf_rpc_state_auth, offset+0, 4,
1187 } /* end of RPC reply */
1190 /* I know, goto is evil but it works as it is. */
1192 /* now we know, that RPC was shorter */
1194 proto_item_set_len(rpc_item, offset - offset_old);
1197 /* create here the program specific sub-tree */
1199 pitem = proto_tree_add_item(tree, proto, offset, END_OF_FRAME);
1201 ptree = proto_item_add_subtree(pitem, ett);
1205 proto_tree_add_item(ptree,
1206 hf_rpc_programversion, 0, 0, vers);
1207 proto_tree_add_uint_format(ptree,
1208 hf_rpc_procedure, 0, 0, proc,
1209 "Procedure: %s (%u)", procname, proc);
1213 /* call a specific dissection */
1214 if (dissect_function != NULL) {
1215 offset = dissect_function(pd, offset, fd, ptree);
1218 /* dissect any remaining bytes (incomplete dissection) as pure data in
1220 dissect_data(pd, offset, fd, ptree);
1226 /* Discard any state we've saved. */
1228 rpc_init_protocol(void)
1230 memset(rpc_call_table, '\0', sizeof rpc_call_table);
1232 rpc_call_firstfree = 0;
1236 /* will be called once from register.c at startup time */
1238 proto_register_rpc(void)
1240 static hf_register_info hf[] = {
1241 { &hf_rpc_lastfrag, {
1242 "Last Fragment", "rpc.lastfrag", FT_BOOLEAN, BASE_NONE,
1243 &yesno, 0, "Last Fragment" }},
1244 { &hf_rpc_fraglen, {
1245 "Fragment Length", "rpc.fraglen", FT_UINT32, BASE_DEC,
1246 NULL, 0, "Fragment Length" }},
1248 "XID", "rpc.xid", FT_UINT32, BASE_HEX,
1250 { &hf_rpc_msgtype, {
1251 "Message Type", "rpc.msgtyp", FT_UINT32, BASE_DEC,
1252 VALS(rpc_msg_type), 0, "Message Type" }},
1253 { &hf_rpc_state_reply, {
1254 "Reply State", "rpc.replystat", FT_UINT32, BASE_DEC,
1255 VALS(rpc_reply_state), 0, "Reply State" }},
1256 { &hf_rpc_state_accept, {
1257 "Accept State", "rpc.state_accept", FT_UINT32, BASE_DEC,
1258 VALS(rpc_accept_state), 0, "Accept State" }},
1259 { &hf_rpc_state_reject, {
1260 "Reject State", "rpc.state_reject", FT_UINT32, BASE_DEC,
1261 VALS(rpc_reject_state), 0, "Reject State" }},
1262 { &hf_rpc_state_auth, {
1263 "Auth State", "rpc.state_auth", FT_UINT32, BASE_DEC,
1264 VALS(rpc_auth_state), 0, "Auth State" }},
1265 { &hf_rpc_version, {
1266 "RPC Version", "rpc.version", FT_UINT32, BASE_DEC,
1267 NULL, 0, "RPC Version" }},
1268 { &hf_rpc_version_min, {
1269 "RPC Version (Minimum)", "rpc.version.min", FT_UINT32,
1270 BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1271 { &hf_rpc_version_max, {
1272 "RPC Version (Maximum)", "rpc.version.max", FT_UINT32,
1273 BASE_DEC, NULL, 0, "RPC Version (Maximum)" }},
1274 { &hf_rpc_program, {
1275 "Program", "rpc.program", FT_UINT32, BASE_DEC,
1276 NULL, 0, "Program" }},
1277 { &hf_rpc_programversion, {
1278 "Program Version", "rpc.programversion", FT_UINT32,
1279 BASE_DEC, NULL, 0, "Program Version" }},
1280 { &hf_rpc_programversion_min, {
1281 "Program Version (Minimum)", "rpc.programversion.min", FT_UINT32,
1282 BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1283 { &hf_rpc_programversion_max, {
1284 "Program Version (Maximum)", "rpc.programversion.max", FT_UINT32,
1285 BASE_DEC, NULL, 0, "Program Version (Maximum)" }},
1286 { &hf_rpc_procedure, {
1287 "Procedure", "rpc.procedure", FT_UINT32, BASE_DEC,
1288 NULL, 0, "Procedure" }},
1289 { &hf_rpc_auth_flavor, {
1290 "Flavor", "rpc.auth.flavor", FT_UINT32, BASE_DEC,
1291 VALS(rpc_auth_flavor), 0, "Flavor" }},
1292 { &hf_rpc_auth_length, {
1293 "Length", "rpc.auth.length", FT_UINT32, BASE_DEC,
1294 NULL, 0, "Length" }},
1295 { &hf_rpc_auth_stamp, {
1296 "Stamp", "rpc.auth.stamp", FT_UINT32, BASE_HEX,
1297 NULL, 0, "Stamp" }},
1298 { &hf_rpc_auth_uid, {
1299 "UID", "rpc.auth.uid", FT_UINT32, BASE_DEC,
1301 { &hf_rpc_auth_gid, {
1302 "GID", "rpc.auth.gid", FT_UINT32, BASE_DEC,
1304 { &hf_rpc_auth_machinename, {
1305 "Machine Name", "rpc.auth.machinename", FT_STRING,
1306 BASE_DEC, NULL, 0, "Machine Name" }},
1308 "Duplicate Transaction", "rpc.dup", FT_UINT32, BASE_DEC,
1309 NULL, 0, "Duplicate Transaction" }},
1310 { &hf_rpc_call_dup, {
1311 "Duplicate Call", "rpc.call.dup", FT_UINT32, BASE_DEC,
1312 NULL, 0, "Duplicate Call" }},
1313 { &hf_rpc_reply_dup, {
1314 "Duplicate Reply", "rpc.reply.dup", FT_UINT32, BASE_DEC,
1315 NULL, 0, "Duplicate Reply" }},
1316 { &hf_rpc_value_follows, {
1317 "Value Follows", "rpc.value_follows", FT_BOOLEAN, BASE_NONE,
1318 &yesno, 0, "Value Follows" }}
1320 static gint *ett[] = {
1328 proto_rpc = proto_register_protocol("Remote Procedure Call", "rpc");
1329 proto_register_field_array(proto_rpc, hf, array_length(hf));
1330 proto_register_subtree_array(ett, array_length(ett));
1331 register_init_routine(&rpc_init_protocol);
1334 * Init the hash tables. Dissectors for RPC protocols must
1335 * have a "handoff registration" routine that registers the
1336 * protocol with RPC; they must not do it in their protocol
1337 * registration routine, as their protocol registration
1338 * routine might be called before this routine is called and
1339 * thus might be called before the hash tables are initialized,
1340 * but it's guaranteed that all protocol registration routines
1341 * will be called before any handoff registration routines
1344 rpc_progs = g_hash_table_new(rpc_prog_hash, rpc_prog_equal);
1345 rpc_procs = g_hash_table_new(rpc_proc_hash, rpc_proc_equal);