Move the test to see if something looks like an ONC RPC request or reply
[obnox/wireshark/wip.git] / packet-rpc.c
1 /* packet-rpc.c
2  * Routines for rpc dissection
3  * Copyright 1999, Uwe Girlich <Uwe.Girlich@philosys.de>
4  * 
5  * $Id: packet-rpc.c,v 1.10 1999/11/14 20:44:52 guy Exp $
6  * 
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@unicom.net>
9  * Copyright 1998 Gerald Combs
10  * 
11  * Copied from packet-smb.c
12  * 
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.
17  * 
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.
22  * 
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.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
34 #endif
35
36 #include <glib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include "packet.h"
40 #include "conversation.h"
41 #include "packet-rpc.h"
42
43
44 const value_string rpc_msg_type[3] = {
45         { RPC_CALL, "Call" },
46         { RPC_REPLY, "Reply" },
47         { 0, NULL }
48 };
49
50 const value_string rpc_reply_state[3] = {
51         { MSG_ACCEPTED, "accepted" },
52         { MSG_DENIED, "denied" },
53         { 0, NULL }
54 };
55
56 const value_string rpc_auth_flavor[5] = {
57         { AUTH_NULL, "AUTH_NULL" },
58         { AUTH_UNIX, "AUTH_UNIX" },
59         { AUTH_SHORT, "AUTH_SHORT" },
60         { AUTH_DES, "AUTH_DES" },
61         { 0, NULL }
62 };
63
64 const value_string rpc_accept_state[6] = {
65         { SUCCESS, "RPC executed successfully" },
66         { PROG_UNAVAIL, "remote hasn't exported program" },
67         { PROG_MISMATCH, "remote can't support version #" },
68         { PROC_UNAVAIL, "program can't support procedure" },
69         { GARBAGE_ARGS, "procedure can't decode params" },
70         { 0, NULL }
71 };
72
73 const value_string rpc_reject_state[3] = {
74         { RPC_MISMATCH, "RPC_MISMATCH" },
75         { AUTH_ERROR, "AUTH_ERROR" },
76         { 0, NULL }
77 };
78
79 const value_string rpc_auth_state[6] = {
80         { AUTH_BADCRED, "bad credential (seal broken)" },
81         { AUTH_REJECTEDCRED, "client must begin new session" },
82         { AUTH_BADVERF, "bad verifier (seal broken)" },
83         { AUTH_REJECTEDVERF, "verifier expired or replayed" },
84         { AUTH_TOOWEAK, "rejected for security reasons" },
85         { 0, NULL }
86 };
87
88
89 /* the protocol number */
90 static int proto_rpc = -1;
91
92
93 /* Hash table with info on RPC program numbers */
94 GHashTable *rpc_progs;
95
96 /* Hash table with info on RPC procedure numbers */
97 GHashTable *rpc_procs;
98
99
100 /***********************************/
101 /* Hash array with procedure names */
102 /***********************************/
103
104 /* compare 2 keys */
105 gint
106 rpc_proc_equal(gconstpointer k1, gconstpointer k2)
107 {
108         rpc_proc_info_key* key1 = (rpc_proc_info_key*) k1;
109         rpc_proc_info_key* key2 = (rpc_proc_info_key*) k2;
110
111         return ((key1->prog == key2->prog && 
112                 key1->vers == key2->vers &&
113                 key1->proc == key2->proc) ?
114         TRUE : FALSE);
115 }
116
117 /* calculate a hash key */
118 guint
119 rpc_proc_hash(gconstpointer k)
120 {
121         rpc_proc_info_key* key = (rpc_proc_info_key*) k;
122
123         return (key->prog ^ (key->vers<<16) ^ (key->proc<<24));
124 }
125
126
127 /* insert some entries */
128 void
129 rpc_init_proc_table(guint prog, guint vers, const vsff *proc_table)
130 {
131         const vsff *proc;
132
133         for (proc = proc_table ; proc->strptr!=NULL; proc++) {
134                 rpc_proc_info_key *key;
135                 rpc_proc_info_value *value;
136
137                 key = (rpc_proc_info_key *) g_malloc(sizeof(rpc_proc_info_key));
138                 key->prog = prog;
139                 key->vers = vers;
140                 key->proc = proc->value;
141
142                 value = (rpc_proc_info_value *) g_malloc(sizeof(rpc_proc_info_value));
143                 value->name = proc->strptr;
144                 value->dissect_call = proc->dissect_call;
145                 value->dissect_reply = proc->dissect_reply;
146
147                 g_hash_table_insert(rpc_procs,key,value);
148         }
149 }
150
151 /*----------------------------------------*/
152 /* end of Hash array with procedure names */
153 /*----------------------------------------*/
154
155
156 /*********************************/
157 /* Hash array with program names */
158 /*********************************/
159
160 /* compare 2 keys */
161 gint
162 rpc_prog_equal(gconstpointer k1, gconstpointer k2)
163 {
164         rpc_prog_info_key* key1 = (rpc_prog_info_key*) k1;
165         rpc_prog_info_key* key2 = (rpc_prog_info_key*) k2;
166
167         return ((key1->prog == key2->prog) ?
168         TRUE : FALSE);
169 }
170
171
172 /* calculate a hash key */
173 guint
174 rpc_prog_hash(gconstpointer k)
175 {
176         rpc_prog_info_key* key = (rpc_prog_info_key*) k;
177
178         return (key->prog);
179 }
180
181
182 void
183 rpc_init_prog(int proto, guint32 prog, int ett)
184 {
185         rpc_prog_info_key *key;
186         rpc_prog_info_value *value;
187
188         key = (rpc_prog_info_key *) g_malloc(sizeof(rpc_prog_info_key));
189         key->prog = prog;
190
191         value = (rpc_prog_info_value *) g_malloc(sizeof(rpc_prog_info_value));
192         value->proto = proto;
193         value->ett = ett;
194         value->progname = proto_registrar_get_abbrev(proto);
195
196         g_hash_table_insert(rpc_progs,key,value);
197 }
198
199 /*      return the name associated with a previously registered program. This
200         should probably eventually be expanded to use the rpc YP/NIS map
201         so that it can give names for programs not handled by ethereal */
202 char *rpc_prog_name(guint32 prog)
203 {
204         char *progname = NULL;
205         rpc_prog_info_key       rpc_prog_key;
206         rpc_prog_info_value     *rpc_prog;
207
208         rpc_prog_key.prog = prog;
209         if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
210                 progname = "Unknown";
211         }
212         else {
213                 progname = rpc_prog->progname;
214         }
215         return progname;
216 }
217
218
219 /*--------------------------------------*/
220 /* end of Hash array with program names */
221 /*--------------------------------------*/
222
223
224 /* Placeholder for future dissectors.
225 It should vanish, if they are finally present. Up to this point, this
226 minimal variant serves as a detector for RPC services and can even find
227 request/reply pairs. */
228
229 #define NLM_PROGRAM     100021
230
231 static int proto_nlm = -1;
232
233 void init_incomplete_dissect(void)
234 {
235         proto_nlm = proto_register_protocol("Network Lock Manager", "NLM");
236         rpc_init_prog(proto_nlm, NLM_PROGRAM, ETT_NLM);
237 }
238
239
240 /*
241  * Init the hash tables. It will be called from ethereal_proto_init().
242  * ethereal_proto_init() calls later proto_init(), which calls 
243  * register_all_protocols().
244  * The proto_register_<some rpc program> functions use these hash tables
245  * here, so we need this order!
246  */
247 void
248 init_dissect_rpc()
249 {
250         rpc_progs = g_hash_table_new(rpc_prog_hash, rpc_prog_equal);
251         rpc_procs = g_hash_table_new(rpc_proc_hash, rpc_proc_equal);
252 }
253
254  
255 /* static array, first quick implementation, I'll switch over to GList soon */ 
256 rpc_call_info rpc_call_table[RPC_CALL_TABLE_LENGTH];
257 guint32 rpc_call_index = 0;
258 guint32 rpc_call_firstfree = 0;
259
260 void
261 rpc_call_insert(rpc_call_info *call)
262 {
263         /* some space left? */
264         if (rpc_call_firstfree<RPC_CALL_TABLE_LENGTH) {
265                 /* some space left */
266                 /* take the first free entry */
267                 rpc_call_index = rpc_call_firstfree;
268                 /* increase this limit */
269                 rpc_call_firstfree++;
270                 /* rpc_call_firstfree may now be RPC_CALL_TABLE_LENGTH */
271         }
272         else {
273                 /* no space left */
274                 /* the next entry, with wrap around */
275                 rpc_call_index = (rpc_call_index+1) % rpc_call_firstfree;
276         }
277                 
278         /* put the entry in */
279         memcpy(&rpc_call_table[rpc_call_index],call,sizeof(*call));
280         return;
281 }
282
283
284 rpc_call_info*
285 rpc_call_lookup(rpc_call_info *call)
286 {
287         int i;
288
289         i = rpc_call_index;
290         do {
291                 if (
292                         rpc_call_table[i].xid == call->xid &&
293                         rpc_call_table[i].conversation == call->conversation
294                 ) {
295                         return &rpc_call_table[i];
296                 }
297                 if (rpc_call_firstfree) {
298                         /* decrement by one, go to rpc_call_firstfree-1 
299                            at the start of the list */
300                         i = (i-1+rpc_call_firstfree) % rpc_call_firstfree;
301                 }
302         } while (i!=rpc_call_index);
303         return NULL;
304 }
305
306
307 unsigned int
308 roundup(unsigned int a)
309 {
310         unsigned int mod = a % 4;
311         return a + ((mod)? 4-mod : 0);
312 }
313
314
315 int
316 dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
317 char* name, char* type)
318 {
319         guint32 value;
320
321         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
322         value = EXTRACT_UINT(pd, offset+0);
323
324         if (tree) {
325                 proto_tree_add_text(tree, offset, 4,
326                 "%s (%s): %u", name, type, value);
327         }
328
329         offset += 4;
330         return offset;
331 }
332
333
334 int
335 dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
336 char* name, char* type)
337 {
338         guint32 value_low;
339         guint32 value_high;
340
341         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
342         value_high = EXTRACT_UINT(pd, offset+0);
343         value_low = EXTRACT_UINT(pd, offset+4);
344
345         if (tree) {
346                 if (value_high)
347                         proto_tree_add_text(tree, offset, 8,
348                                 "%s (%s): %x%08x", name, type, value_high, value_low);
349                 else
350                         proto_tree_add_text(tree, offset, 8,
351                                 "%s (%s): %u", name, type, value_low);
352         }
353
354         offset += 8;
355         return offset;
356 }
357
358
359
360 /* arbitrary limit */
361 #define RPC_STRING_MAXBUF 2048
362
363 int
364 dissect_rpc_string(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
365 {
366         proto_item *string_item;
367         proto_tree *string_tree = NULL;
368
369         guint32 string_length;
370         guint32 string_fill;
371         guint32 string_length_full;
372         char string_buffer[RPC_STRING_MAXBUF];
373
374         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
375         string_length = EXTRACT_UINT(pd,offset+0);
376         string_length_full = roundup(string_length);
377         string_fill = string_length_full - string_length;
378         if (!BYTES_ARE_IN_FRAME(offset+4,string_length_full)) return offset;
379         if (string_length>=sizeof(string_buffer)) return offset;
380         memcpy(string_buffer,pd+offset+4,string_length);
381         string_buffer[string_length] = '\0';
382         if (tree) {
383                 string_item = proto_tree_add_text(tree,offset+0,
384                         4+string_length_full,
385                         "%s: %s", name, string_buffer);
386                 if (string_item) {
387                         string_tree = proto_item_add_subtree(string_item, ETT_RPC_STRING);
388                 }
389         }
390         if (string_tree) {
391                 proto_tree_add_text(string_tree,offset+0,4,
392                         "length: %u", string_length);
393                 proto_tree_add_text(string_tree,offset+4,string_length,
394                         "text: %s", string_buffer);
395                 if (string_fill)
396                         proto_tree_add_text(string_tree,offset+4+string_length,string_fill,
397                                 "fill bytes: opaque data");
398         }
399
400         offset += 4 + string_length_full;
401         return offset;
402 }
403
404 int
405 dissect_rpc_string_item(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hfindex)
406 {
407         proto_item *string_item;
408         proto_tree *string_tree = NULL;
409
410         guint32 string_length;
411         guint32 string_fill;
412         guint32 string_length_full;
413         char string_buffer[RPC_STRING_MAXBUF];
414
415         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
416         string_length = EXTRACT_UINT(pd,offset+0);
417         string_length_full = roundup(string_length);
418         string_fill = string_length_full - string_length;
419         if (!BYTES_ARE_IN_FRAME(offset+4,string_length_full)) return offset;
420         if (string_length>=sizeof(string_buffer)) return offset;
421         memcpy(string_buffer,pd+offset+4,string_length);
422         string_buffer[string_length] = '\0';
423         if (tree) {
424                 string_item = proto_tree_add_text(tree,offset+0,
425                         4+string_length_full,
426                         "%s: %s", proto_registrar_get_name(hfindex), string_buffer);
427                 proto_tree_add_item_hidden(tree, hfindex, offset+4,
428                         string_length, string_buffer);
429                 if (string_item) {
430                         string_tree = proto_item_add_subtree(string_item, ETT_RPC_STRING);
431                 }
432         }
433         if (string_tree) {
434                 proto_tree_add_text(string_tree,offset+0,4,
435                         "length: %u", string_length);
436                 proto_tree_add_text(string_tree,offset+4,string_length,
437                         "text: %s", string_buffer);
438                 if (string_fill)
439                         proto_tree_add_text(string_tree,offset+4+string_length,string_fill,
440                                 "fill bytes: opaque data");
441         }
442
443         offset += 4 + string_length_full;
444         return offset;
445 }
446
447
448 void
449 dissect_rpc_auth( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
450 {
451         guint flavor;
452         guint length;
453         guint length_full;
454
455         /* both checks are made outside */
456         /* if (!BYTES_ARE_IN_FRAME(offset,8)) return; */
457         flavor = EXTRACT_UINT(pd,offset+0);
458         length = EXTRACT_UINT(pd,offset+4);
459         length_full = roundup(length);
460         /* if (!BYTES_ARE_IN_FRAME(offset+8,full_length)) return; */
461
462         if (tree) {
463                 proto_tree_add_text(tree,offset+0,4,
464                 "Flavor: %s (%u)", val_to_str(flavor,rpc_auth_flavor,"Unknown"),flavor);
465                 proto_tree_add_text(tree,offset+4,4,
466                         "Length: %u", length);
467         }
468
469         offset += 8;
470
471         switch (flavor) {
472                 case AUTH_UNIX: {
473                         guint stamp;
474                         guint uid;
475                         guint gid;
476                         guint gids_count;
477                         guint gids_i;
478                         guint gids_entry;
479                         proto_item *gitem;
480                         proto_tree *gtree = NULL;
481
482                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
483                         stamp = EXTRACT_UINT(pd,offset+0);
484                         if (tree)
485                                 proto_tree_add_text(tree,offset+0,4,
486                                         "stamp: 0x%08x", stamp);
487                         offset += 4;
488
489                         offset = dissect_rpc_string(pd,offset,fd,tree,"machinename");
490
491                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
492                         uid = EXTRACT_UINT(pd,offset+0);
493                         if (tree)
494                                 proto_tree_add_text(tree,offset+0,4,
495                                         "uid: %u", uid);
496                         offset += 4;
497
498                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
499                         gid = EXTRACT_UINT(pd,offset+0);
500                         if (tree)
501                                 proto_tree_add_text(tree,offset+0,4,
502                                         "gid: %u", gid);
503                         offset += 4;
504
505                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
506                         gids_count = EXTRACT_UINT(pd,offset+0);
507                         if (tree) {
508                                 gitem = proto_tree_add_text(tree, offset, 4+gids_count*4,
509                                 "gids");
510                                 gtree = proto_item_add_subtree(gitem, ETT_RPC_GIDS);
511                         }
512                         offset += 4;
513                         if (!BYTES_ARE_IN_FRAME(offset,4*gids_count)) return;
514                         for (gids_i = 0 ; gids_i < gids_count ; gids_i++) {
515                                 gids_entry = EXTRACT_UINT(pd,offset+0);
516                                 if (gtree)
517                                 proto_tree_add_text(gtree, offset, 4, 
518                                         "%u", gids_entry);
519                                 offset+=4;
520                         }
521                         /* how can I NOW change the gitem to print a list with
522                                 the first 16 gids? */
523                 }
524                 break;
525                 /*
526                 case AUTH_SHORT:
527
528                 break;
529                 */
530                 /* I have no tcpdump file with such a packet to verify the
531                         info from the RFC 1050 */
532                 /*
533                 case AUTH_DES:
534
535                 break;
536                 */
537                 default:
538                         if (length_full) {
539                                 if (tree)
540                                 proto_tree_add_text(tree,offset,
541                                 length_full, "opaque data");
542                         }
543         }
544 }
545
546 int
547 dissect_rpc_cred( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
548 {
549         guint length;
550         guint length_full;
551         proto_item *citem;
552         proto_tree *ctree;
553
554         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
555         length = EXTRACT_UINT(pd,offset+4);
556         length_full = roundup(length);
557         if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
558
559         if (tree) {
560                 citem = proto_tree_add_text(tree, offset, 8+length_full,
561                         "Credentials");
562                 ctree = proto_item_add_subtree(citem, ETT_RPC_CRED);
563                 dissect_rpc_auth(pd, offset, fd, ctree);
564         }
565         offset += 8 + length_full;
566
567         return offset;
568 }
569
570
571 int
572 dissect_rpc_verf( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
573 {
574         unsigned int length;
575         unsigned int length_full;
576         proto_item *vitem;
577         proto_tree *vtree;
578
579         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
580         length = EXTRACT_UINT(pd,offset+4);
581         length_full = roundup(length);
582         if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
583
584         if (tree) {
585                 vitem = proto_tree_add_text(tree, offset, 8+length_full,
586                         "Verifier");
587                 vtree = proto_item_add_subtree(vitem, ETT_RPC_VERF);
588                 dissect_rpc_auth(pd, offset, fd, vtree);
589         }
590         offset += 8 + length_full;
591
592         return offset;
593 }
594
595
596 gboolean
597 dissect_rpc( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
598 {
599         guint32 msg_type;
600         rpc_call_info rpc_key;
601         rpc_call_info *rpc_call = NULL;
602         rpc_prog_info_value *rpc_prog = NULL;
603         rpc_prog_info_key rpc_prog_key;
604
605         unsigned int xid;
606         unsigned int rpcvers;
607         unsigned int prog;
608         unsigned int vers = 0;
609         unsigned int proc = 0;
610         int     proto = 0;
611         int     ett = 0;
612
613         unsigned int reply_state;
614         unsigned int accept_state;
615         unsigned int reject_state;
616
617         char *msg_type_name = NULL;
618         char *progname;
619         char *procname = NULL;
620         static char procname_static[20];
621
622         unsigned int vers_low;
623         unsigned int vers_high;
624
625         unsigned int auth_state;
626
627         proto_item *rpc_item=NULL;
628         proto_tree *rpc_tree = NULL;
629
630         proto_item *pitem=NULL;
631         proto_tree *ptree = NULL;
632         int offset_old = offset;
633
634         rpc_call_info   rpc_call_msg;
635         rpc_proc_info_key       key;
636         rpc_proc_info_value     *value = NULL;
637         conversation_t* conversation;
638
639         dissect_function_t *dissect_function = NULL;
640
641         /*
642          * Check to see whether this looks like an RPC call or reply.
643          */
644         if (!BYTES_ARE_IN_FRAME(offset,8)) {
645                 /* Captured data in packet isn't enough to let us tell. */
646                 return FALSE;
647         }
648
649         /* both directions need at least this */
650         msg_type = EXTRACT_UINT(pd,offset+4);
651
652         switch (msg_type) {
653
654         case RPC_CALL:
655                 /* check for RPC call */
656                 if (!BYTES_ARE_IN_FRAME(offset,16)) {
657                         /* Captured data in packet isn't enough to let us
658                            tell. */
659                         return FALSE;
660                 }
661
662                 /* XID can be anything, we don't check it.
663                    We already have the message type.
664                    Check whether an RPC version number of 2 is in the
665                    location where it would be, and that an RPC program
666                    number we know about is in the locaton where it would be. */
667                 rpc_prog_key.prog = EXTRACT_UINT(pd,offset+12);
668                 if (EXTRACT_UINT(pd,offset+8) != 2 ||
669                     ((rpc_prog = g_hash_table_lookup(rpc_progs, &rpc_prog_key))
670                        == NULL)) {
671                         /* They're not, so it's probably not an RPC call. */
672                         return FALSE;
673                 }
674                 break;
675
676         case RPC_REPLY:
677                 /* check for RPC reply */
678                 conversation = find_conversation(&pi.src, &pi.dst,
679                     pi.ptype, pi.srcport, pi.destport);
680                 if (conversation == NULL) {
681                         /* We haven't seen an RPC call for that conversation,
682                            so we can't check for a reply to that call. */
683                         return FALSE;
684                 }
685                 rpc_key.xid = EXTRACT_UINT(pd,offset+0);
686                 rpc_key.conversation = conversation;
687                 if ((rpc_call = rpc_call_lookup(&rpc_key)) == NULL) {
688                         /* The XID doesn't match a call from that
689                            conversation, so it's probably not an RPC reply. */
690                         return FALSE;
691                 }
692                 break;
693
694         default:
695                 /* The putative message type field contains neither
696                    RPC_CALL nor RPC_REPLY, so it's not an RPC call or
697                    reply. */
698                 return FALSE;
699         }
700
701         if (check_col(fd, COL_PROTOCOL))
702                 col_add_str(fd, COL_PROTOCOL, "RPC");
703
704         if (tree) {
705                 rpc_item = proto_tree_add_item(tree, proto_rpc, offset, END_OF_FRAME, NULL);
706                 if (rpc_item) {
707                         rpc_tree = proto_item_add_subtree(rpc_item, ETT_RPC);
708                 }
709         }
710
711         xid      = EXTRACT_UINT(pd,offset+0);
712         if (rpc_tree) {
713                 proto_tree_add_text(rpc_tree,offset+0,4,
714                         "XID: 0x%x (%u)", xid, xid);
715         }
716
717         msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u");
718         if (rpc_tree) {
719                 proto_tree_add_text(rpc_tree,offset+4,4,
720                         "msg_type: %s (%u)",
721                         msg_type_name, msg_type);
722         }
723
724         offset += 8;
725
726         if (msg_type==RPC_CALL) {
727                 /* we know already the proto-entry, the ETT-const,
728                    and "rpc_prog" */
729                 proto = rpc_prog->proto;
730                 ett = rpc_prog->ett;
731                 progname = rpc_prog->progname;
732
733                 rpcvers = EXTRACT_UINT(pd,offset+0);
734                 if (rpc_tree) {
735                         proto_tree_add_text(rpc_tree,offset+0,4,
736                                 "RPC Version: %u", rpcvers);
737                 }
738
739                 prog = EXTRACT_UINT(pd,offset+4);
740                 
741                 if (rpc_tree) {
742                         proto_tree_add_text(rpc_tree,offset+4,4,
743                                 "Program: %s (%u)", progname, prog);
744                 }
745                 
746                 if (check_col(fd, COL_PROTOCOL)) {
747                         /* Set the protocol name to the underlying
748                            program name. */
749                         col_add_fstr(fd, COL_PROTOCOL, "%s", progname);
750                 }
751
752                 if (!BYTES_ARE_IN_FRAME(offset+8,4))
753                         return TRUE;
754                 vers = EXTRACT_UINT(pd,offset+8);
755                 if (rpc_tree) {
756                         proto_tree_add_text(rpc_tree,offset+8,4,
757                                 "Program Version: %u",vers);
758                 }
759
760                 if (!BYTES_ARE_IN_FRAME(offset+12,4))
761                         return TRUE;
762                 proc = EXTRACT_UINT(pd,offset+12);
763
764                 key.prog = prog;
765                 key.vers = vers;
766                 key.proc = proc;
767
768                 value = g_hash_table_lookup(rpc_procs,&key);
769                 if (value != NULL) {
770                         dissect_function = value->dissect_call;
771                         procname = value->name;
772                 }
773                 else {
774                         /* happens only with strange program versions or
775                            non-existing dissectors */
776                         dissect_function = NULL;
777                         sprintf(procname_static, "proc-%u", proc);
778                         procname = procname_static;
779                 }
780                 if (rpc_tree) {
781                         proto_tree_add_text(rpc_tree,offset+12,4,
782                                 "Procedure: %s (%u)", procname, proc);
783                 }
784
785                 if (check_col(fd, COL_INFO)) {
786                         col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
787                                 vers,
788                                 procname,
789                                 msg_type_name,
790                                 xid);
791                 }
792
793                 conversation = find_conversation(&pi.src, &pi.dst, pi.ptype,
794                         pi.srcport, pi.destport);
795                 if (conversation == NULL) {
796                         /* It's not part of any conversation - create a new one. */
797                         conversation = conversation_new(&pi.src, &pi.dst, pi.ptype,
798                                 pi.srcport, pi.destport, NULL);
799                 }
800
801                 /* prepare the key data */
802                 rpc_call_msg.xid = xid;
803                 rpc_call_msg.conversation = conversation;
804
805                 /* look up the request */
806                 if (rpc_call_lookup(&rpc_call_msg)) {
807                         /* duplicate request */
808                         if (check_col(fd, COL_INFO)) {
809                                 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
810                         }
811                 }
812                 else {
813                         /* prepare the value data */
814                         rpc_call_msg.replies = 0;
815                         rpc_call_msg.prog = prog;
816                         rpc_call_msg.vers = vers;
817                         rpc_call_msg.proc = proc;
818                         rpc_call_msg.proc_info = value;
819                         /* store it */
820                         rpc_call_insert(&rpc_call_msg);
821                 }
822
823                 offset += 16;
824
825                 offset = dissect_rpc_cred(pd, offset, fd, rpc_tree);
826                 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
827
828                 /* go to the next dissector */
829                 /* goto dissect_rpc_prog; */
830
831         } /* end of RPC call */
832         else if (msg_type == RPC_REPLY)
833         {
834                 /* we know already the type from the calling routine,
835                    and we already have "rpc_call" set above. */
836                 prog = rpc_call->prog;
837                 vers = rpc_call->vers;
838                 proc = rpc_call->proc;
839                 if (rpc_call->proc_info != NULL) {
840                         dissect_function = rpc_call->proc_info->dissect_reply;
841                         if (rpc_call->proc_info->name != NULL) {
842                                 procname = rpc_call->proc_info->name;
843                         }
844                         else {
845                                 sprintf(procname_static, "proc-%u", proc);
846                                 procname = procname_static;
847                         }
848                 }
849                 else {
850                         dissect_function = NULL;
851                         sprintf(procname_static, "proc-%u", proc);
852                         procname = procname_static;
853                 }
854                 rpc_call->replies++;
855
856                 rpc_prog_key.prog = prog;
857                 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
858                         proto = 0;
859                         ett = 0;
860                         progname = "Unknown";
861                 }
862                 else {
863                         proto = rpc_prog->proto;
864                         ett = rpc_prog->ett;
865                         progname = rpc_prog->progname;
866
867                         if (check_col(fd, COL_PROTOCOL)) {
868                                 /* Set the protocol name to the underlying
869                                    program name. */
870                                 col_add_fstr(fd, COL_PROTOCOL, "%s",
871                                     progname);
872                         }
873                 }
874
875                 if (check_col(fd, COL_INFO)) {
876                         col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
877                                 vers,
878                                 procname,
879                                 msg_type_name,
880                                 xid);
881                 }
882
883                 if (rpc_tree) {
884                         proto_tree_add_text(rpc_tree,0,0,
885                                 "Program: %s (%u)", 
886                                 progname, prog);
887                         proto_tree_add_text(rpc_tree,0,0,
888                                 "Program Version: %u", vers);
889                         proto_tree_add_text(rpc_tree,0,0,
890                                 "Procedure: %s (%u)", procname, proc);
891                 }
892
893                 if (rpc_call->replies>1) {
894                         if (check_col(fd, COL_INFO)) {
895                                 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
896                         }
897                 }
898
899                 if (!BYTES_ARE_IN_FRAME(offset,4))
900                         return TRUE;
901                 reply_state = EXTRACT_UINT(pd,offset+0);
902                 if (rpc_tree) {
903                         proto_tree_add_text(rpc_tree,offset+0, 4,
904                                 "Reply State: %s (%u)",
905                                 val_to_str(reply_state,rpc_reply_state,"Unknown"),
906                                 reply_state);
907                 }
908                 offset += 4;
909
910                 if (reply_state == MSG_ACCEPTED) {
911                         offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
912                         if (!BYTES_ARE_IN_FRAME(offset,4))
913                                 return TRUE;
914                         accept_state = EXTRACT_UINT(pd,offset+0);
915                         if (rpc_tree) {
916                                 proto_tree_add_text(rpc_tree,offset+0, 4,
917                                         "Accept State: %s (%u)", 
918                                         val_to_str(accept_state,rpc_accept_state,"Unknown"),
919                                         accept_state);
920                         }
921                         offset += 4;
922                         switch (accept_state) {
923                                 case SUCCESS:
924                                         /* now goto the lower protocol */
925                                         goto dissect_rpc_prog;
926                                 break;
927                                 case PROG_MISMATCH:
928                                         if (!BYTES_ARE_IN_FRAME(offset,8))
929                                                 return TRUE;
930                                         vers_low = EXTRACT_UINT(pd,offset+0);
931                                         vers_high = EXTRACT_UINT(pd,offset+4);
932                                         if (rpc_tree) {
933                                                 proto_tree_add_text(rpc_tree,
934                                                         offset+0, 4,
935                                                         "min. Program Version: %u",
936                                                         vers_low);
937                                                 proto_tree_add_text(rpc_tree,
938                                                         offset+4, 4,
939                                                         "max. Program Version: %u",
940                                                         vers_high);
941                                         }
942                                         offset += 8;
943                                 break;
944                                 default:
945                                         /* void */
946                                 break;
947                         }
948                 } else if (reply_state == MSG_DENIED) {
949                         if (!BYTES_ARE_IN_FRAME(offset,4))
950                                 return TRUE;
951                         reject_state = EXTRACT_UINT(pd,offset+0);
952                         if (rpc_tree) {
953                                 proto_tree_add_text(rpc_tree, offset+0, 4,
954                                         "Reject State: %s (%u)",
955                                         val_to_str(reject_state,rpc_reject_state,"Unknown"),
956                                         reject_state);
957                         }
958                         offset += 4;
959
960                         if (reject_state==RPC_MISMATCH) {
961                                 if (!BYTES_ARE_IN_FRAME(offset,8))
962                                         return TRUE;
963                                 vers_low = EXTRACT_UINT(pd,offset+0);
964                                 vers_high = EXTRACT_UINT(pd,offset+4);
965                                 if (rpc_tree) {
966                                         proto_tree_add_text(rpc_tree,
967                                                 offset+0, 4,
968                                                 "min. RPC Version: %u",
969                                                 vers_low);
970                                         proto_tree_add_text(rpc_tree,
971                                                 offset+4, 4,
972                                                 "max. RPC Version: %u",
973                                                 vers_high);
974                                 }
975                                 offset += 8;
976                         } else if (reject_state==AUTH_ERROR) {
977                                 if (!BYTES_ARE_IN_FRAME(offset,4))
978                                         return TRUE;
979                                 auth_state = EXTRACT_UINT(pd,offset+0);
980                                 if (rpc_tree) {
981                                         proto_tree_add_text(rpc_tree,
982                                                 offset+0, 4,
983                                                 "Authentication error: %s (%u)",
984                                                 val_to_str(auth_state,rpc_auth_state,"Unknown"),
985                                                 auth_state);
986                                 }
987                                 offset += 4;
988                         }
989                 } 
990         } /* end of RPC reply */
991
992 dissect_rpc_prog:
993         /* I know, goto is evil but it works as it is. */
994
995         /* now we know, that RPC was shorter */
996         if (rpc_item) {
997                 proto_item_set_len(rpc_item, offset - offset_old);
998         }
999
1000         /* create here the program specific sub-tree */
1001         if (tree) {
1002                 pitem = proto_tree_add_item(tree, proto, offset, END_OF_FRAME);
1003                 if (pitem)
1004                         ptree = proto_item_add_subtree(pitem, ett);
1005                 }
1006
1007         /* call a specific dissection */
1008         if (dissect_function != NULL) {
1009                 offset = dissect_function(pd, offset, fd, ptree);
1010         }
1011
1012         /* dissect any remaining bytes (incomplete dissection) as pure data in
1013            the ptree */
1014         dissect_data(pd, offset, fd, ptree);
1015
1016         return TRUE;
1017 }
1018
1019 /* will be called from file.c on every new file open */
1020 void
1021 rpc_init_protocol(void)
1022 {
1023         rpc_call_index = 0;
1024         rpc_call_firstfree = 0;
1025 }
1026
1027
1028 /* will be called once from register.c at startup time */
1029 void
1030 proto_register_rpc(void)
1031 {
1032         proto_rpc = proto_register_protocol("Remote Procedure Call", "rpc");
1033
1034         /* please remove this, if all specific dissectors are ready */
1035         init_incomplete_dissect();
1036 }