Give "dissect_rpc_string()" an extra "char **" argument; if it's
[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.26 2000/01/22 05:49:06 guy Exp $
6  * 
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
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 <ctype.h>
40 #include "packet.h"
41 #include "conversation.h"
42 #include "packet-rpc.h"
43
44
45 #define RPC_RM_FRAGLEN  0x7fffffffL
46
47 static struct true_false_string yesno = { "Yes", "No" };
48
49
50 static const value_string rpc_msg_type[3] = {
51         { RPC_CALL, "Call" },
52         { RPC_REPLY, "Reply" },
53         { 0, NULL }
54 };
55
56 static const value_string rpc_reply_state[3] = {
57         { MSG_ACCEPTED, "accepted" },
58         { MSG_DENIED, "denied" },
59         { 0, NULL }
60 };
61
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" },
67         { 0, NULL }
68 };
69
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" },
76         { 0, NULL }
77 };
78
79 static const value_string rpc_reject_state[3] = {
80         { RPC_MISMATCH, "RPC_MISMATCH" },
81         { AUTH_ERROR, "AUTH_ERROR" },
82         { 0, NULL }
83 };
84
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" },
91         { 0, NULL }
92 };
93
94
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
123 static gint ett_rpc = -1;
124 static gint ett_rpc_string = -1;
125 static gint ett_rpc_cred = -1;
126 static gint ett_rpc_verf = -1;
127 static gint ett_rpc_gids = -1;
128
129 /* Hash table with info on RPC program numbers */
130 static GHashTable *rpc_progs;
131
132 /* Hash table with info on RPC procedure numbers */
133 static GHashTable *rpc_procs;
134
135
136 /***********************************/
137 /* Hash array with procedure names */
138 /***********************************/
139
140 /* compare 2 keys */
141 gint
142 rpc_proc_equal(gconstpointer k1, gconstpointer k2)
143 {
144         rpc_proc_info_key* key1 = (rpc_proc_info_key*) k1;
145         rpc_proc_info_key* key2 = (rpc_proc_info_key*) k2;
146
147         return ((key1->prog == key2->prog && 
148                 key1->vers == key2->vers &&
149                 key1->proc == key2->proc) ?
150         TRUE : FALSE);
151 }
152
153 /* calculate a hash key */
154 guint
155 rpc_proc_hash(gconstpointer k)
156 {
157         rpc_proc_info_key* key = (rpc_proc_info_key*) k;
158
159         return (key->prog ^ (key->vers<<16) ^ (key->proc<<24));
160 }
161
162
163 /* insert some entries */
164 void
165 rpc_init_proc_table(guint prog, guint vers, const vsff *proc_table)
166 {
167         const vsff *proc;
168
169         for (proc = proc_table ; proc->strptr!=NULL; proc++) {
170                 rpc_proc_info_key *key;
171                 rpc_proc_info_value *value;
172
173                 key = (rpc_proc_info_key *) g_malloc(sizeof(rpc_proc_info_key));
174                 key->prog = prog;
175                 key->vers = vers;
176                 key->proc = proc->value;
177
178                 value = (rpc_proc_info_value *) g_malloc(sizeof(rpc_proc_info_value));
179                 value->name = proc->strptr;
180                 value->dissect_call = proc->dissect_call;
181                 value->dissect_reply = proc->dissect_reply;
182
183                 g_hash_table_insert(rpc_procs,key,value);
184         }
185 }
186
187 /*----------------------------------------*/
188 /* end of Hash array with procedure names */
189 /*----------------------------------------*/
190
191
192 /*********************************/
193 /* Hash array with program names */
194 /*********************************/
195
196 /* compare 2 keys */
197 gint
198 rpc_prog_equal(gconstpointer k1, gconstpointer k2)
199 {
200         rpc_prog_info_key* key1 = (rpc_prog_info_key*) k1;
201         rpc_prog_info_key* key2 = (rpc_prog_info_key*) k2;
202
203         return ((key1->prog == key2->prog) ?
204         TRUE : FALSE);
205 }
206
207
208 /* calculate a hash key */
209 guint
210 rpc_prog_hash(gconstpointer k)
211 {
212         rpc_prog_info_key* key = (rpc_prog_info_key*) k;
213
214         return (key->prog);
215 }
216
217
218 void
219 rpc_init_prog(int proto, guint32 prog, int ett)
220 {
221         rpc_prog_info_key *key;
222         rpc_prog_info_value *value;
223         char *uc_progname = NULL, *lc_progname = NULL;
224
225         key = (rpc_prog_info_key *) g_malloc(sizeof(rpc_prog_info_key));
226         key->prog = prog;
227
228         value = (rpc_prog_info_value *) g_malloc(sizeof(rpc_prog_info_value));
229         value->proto = proto;
230         value->ett = ett;
231
232         lc_progname = proto_registrar_get_abbrev(proto);
233         if ( lc_progname )
234         {
235                 int i;
236                 uc_progname = strdup(lc_progname);
237                 for (i=0; i<strlen(uc_progname); i++)
238                 {
239                         uc_progname[i] = toupper(uc_progname[i]);
240                 }
241         }
242         value->progname = uc_progname;
243
244         g_hash_table_insert(rpc_progs,key,value);
245 }
246
247 /*      return the name associated with a previously registered program. This
248         should probably eventually be expanded to use the rpc YP/NIS map
249         so that it can give names for programs not handled by ethereal */
250 char *rpc_prog_name(guint32 prog)
251 {
252         char *progname = NULL;
253         rpc_prog_info_key       rpc_prog_key;
254         rpc_prog_info_value     *rpc_prog;
255
256         rpc_prog_key.prog = prog;
257         if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
258                 progname = "Unknown";
259         }
260         else {
261                 progname = rpc_prog->progname;
262         }
263         return progname;
264 }
265
266
267 /*--------------------------------------*/
268 /* end of Hash array with program names */
269 /*--------------------------------------*/
270
271
272 /*
273  * Init the hash tables. It will be called from ethereal_proto_init().
274  * ethereal_proto_init() calls later proto_init(), which calls 
275  * register_all_protocols().
276  * The proto_register_<some rpc program> functions use these hash tables
277  * here, so we need this order!
278  */
279 void
280 init_dissect_rpc()
281 {
282         rpc_progs = g_hash_table_new(rpc_prog_hash, rpc_prog_equal);
283         rpc_procs = g_hash_table_new(rpc_proc_hash, rpc_proc_equal);
284 }
285
286  
287 /* static array, first quick implementation, I'll switch over to GList soon */ 
288 rpc_call_info rpc_call_table[RPC_CALL_TABLE_LENGTH];
289 guint32 rpc_call_index = 0;
290 guint32 rpc_call_firstfree = 0;
291
292 void
293 rpc_call_insert(rpc_call_info *call)
294 {
295         /* some space left? */
296         if (rpc_call_firstfree<RPC_CALL_TABLE_LENGTH) {
297                 /* some space left */
298                 /* take the first free entry */
299                 rpc_call_index = rpc_call_firstfree;
300                 /* increase this limit */
301                 rpc_call_firstfree++;
302                 /* rpc_call_firstfree may now be RPC_CALL_TABLE_LENGTH */
303         }
304         else {
305                 /* no space left */
306                 /* the next entry, with wrap around */
307                 rpc_call_index = (rpc_call_index+1) % rpc_call_firstfree;
308         }
309                 
310         /* put the entry in */
311         memcpy(&rpc_call_table[rpc_call_index],call,sizeof(*call));
312         return;
313 }
314
315
316 rpc_call_info*
317 rpc_call_lookup(rpc_call_info *call)
318 {
319         int i;
320
321         i = rpc_call_index;
322         do {
323                 if (
324                         rpc_call_table[i].xid == call->xid &&
325                         rpc_call_table[i].conversation == call->conversation
326                 ) {
327                         return &rpc_call_table[i];
328                 }
329                 if (rpc_call_firstfree) {
330                         /* decrement by one, go to rpc_call_firstfree-1 
331                            at the start of the list */
332                         i = (i-1+rpc_call_firstfree) % rpc_call_firstfree;
333                 }
334         } while (i!=rpc_call_index);
335         return NULL;
336 }
337
338
339 unsigned int
340 rpc_roundup(unsigned int a)
341 {
342         unsigned int mod = a % 4;
343         return a + ((mod)? 4-mod : 0);
344 }
345
346
347 int
348 dissect_rpc_bool(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
349 int hfindex)
350 {
351         guint32 value;
352
353         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
354         value = EXTRACT_UINT(pd, offset+0);
355         if (tree)
356                 proto_tree_add_item(tree, hfindex, offset, 4, value);
357         offset += 4;
358
359         return offset;
360 }
361
362
363 int
364 dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
365 char* name, char* type)
366 {
367         guint32 value;
368
369         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
370         value = EXTRACT_UINT(pd, offset+0);
371
372         if (tree) {
373                 proto_tree_add_text(tree, offset, 4,
374                 "%s: %u", name, value);
375         }
376
377         offset += 4;
378         return offset;
379 }
380
381
382 int
383 dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
384 char* name, char* type)
385 {
386         guint32 value_low;
387         guint32 value_high;
388
389         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
390         value_high = EXTRACT_UINT(pd, offset+0);
391         value_low = EXTRACT_UINT(pd, offset+4);
392
393         if (tree) {
394                 if (value_high)
395                         proto_tree_add_text(tree, offset, 8,
396                                 "%s: 0x%x%08x", name, value_high, value_low);
397                 else
398                         proto_tree_add_text(tree, offset, 8,
399                                 "%s: %u", name, value_low);
400         }
401
402         offset += 8;
403         return offset;
404 }
405
406
407 static int
408 dissect_rpc_opaque_data(const u_char *pd, int offset, frame_data *fd,
409     proto_tree *tree, int hfindex, gboolean string_data,
410     char **string_buffer_ret)
411 {
412         proto_item *string_item = NULL;
413         proto_tree *string_tree = NULL;
414         int old_offset = offset;
415
416         int length_truncated = 0;
417
418         int string_truncated = 0;
419         guint32 string_length = 0;
420         guint32 string_length_full;
421         guint32 string_length_packet;
422         guint32 string_length_copy = 0;
423
424         int fill_truncated = 0;
425         guint32 fill_length  = 0;
426         guint32 fill_length_packet  = 0;
427         guint32 fill_length_copy  = 0;
428
429         char *string_buffer = NULL;
430         char *string_buffer_print = NULL;
431
432         if (BYTES_ARE_IN_FRAME(offset,4)) {
433                 string_length = EXTRACT_UINT(pd,offset+0);
434                 string_length_full = rpc_roundup(string_length);
435                 string_length_packet = pi.captured_len - (offset + 4);
436                 if (string_length_packet < string_length) {
437                         /* truncated string */
438                         string_truncated = 1;
439                         string_length_copy = string_length_packet;
440                         fill_truncated = 2;
441                         fill_length = 0;
442                         fill_length_packet = 0;
443                         fill_length_copy = 0;
444                 }
445                 else {
446                         /* full string data */
447                         string_truncated = 0;
448                         string_length_copy = string_length;
449                         fill_length = string_length_full - string_length;
450                         fill_length_packet = pi.captured_len - (offset + 4 + string_length);
451                         if (fill_length_packet < fill_length) {
452                                 /* truncated fill bytes */
453                                 fill_length_copy = fill_length_packet;
454                                 fill_truncated = 1;
455                         }
456                         else {
457                                 /* full fill bytes */
458                                 fill_length_copy = fill_length;
459                                 fill_truncated = 0;
460                         }
461                 }
462                 string_buffer = (char*)g_malloc(string_length_copy + 
463                         (string_data ? 1 : 0));
464                 memcpy(string_buffer,pd+offset+4,string_length_copy);
465                 if (string_data)
466                         string_buffer[string_length_copy] = '\0';
467
468                 /* calculate a nice printable string */
469                 if (string_length) {
470                         if (string_length != string_length_copy) {
471                                 if (string_data) {
472                                         /* alloc maximum data area */
473                                         string_buffer_print = (char*)g_malloc(string_length_copy + 12 + 1);
474                                         /* copy over the data */
475                                         memcpy(string_buffer_print,string_buffer,string_length_copy);
476                                         /* append a 0 byte for sure printing */
477                                         string_buffer_print[string_length_copy] = '\0';
478                                         /* append <TRUNCATED> */
479                                         /* This way, we get the TRUNCATED even
480                                            in the case of totally wrong packets,
481                                            where \0 are inside the string.
482                                            TRUNCATED will appear at the
483                                            first \0 or at the end (where we 
484                                            put the securing \0).
485                                         */
486                                         strcat(string_buffer_print,"<TRUNCATED>");
487                                 }
488                                 else {
489                                         string_buffer_print = g_strdup("<DATA><TRUNCATED>");
490                                 }
491                         }
492                         else {
493                                 if (string_data) {
494                                         string_buffer_print = g_strdup(string_buffer);
495                                 }
496                                 else {
497                                         string_buffer_print = g_strdup("<DATA>");
498                                 }
499                         }
500                 }
501                 else {
502                         string_buffer_print = g_strdup("<EMPTY>");
503                 }
504         }
505         else {
506                 length_truncated = 1;
507                 string_truncated = 2;
508                 fill_truncated = 2;
509                 string_buffer = g_strdup("");
510                 string_buffer_print = g_strdup("<TRUNCATED>");
511         }
512
513         if (tree) {
514                 string_item = proto_tree_add_text(tree,offset+0, END_OF_FRAME,
515                         "%s: %s", proto_registrar_get_name(hfindex), string_buffer_print);
516                 if (string_data) {
517                         proto_tree_add_item_hidden(tree, hfindex, offset+4,
518                                 string_length_copy, string_buffer);
519                 }
520                 if (string_item) {
521                         string_tree = proto_item_add_subtree(string_item, ett_rpc_string);
522                 }
523         }
524         if (length_truncated) {
525                 if (string_tree)
526                         proto_tree_add_text(string_tree,
527                                 offset,pi.captured_len-offset,
528                                 "length: <TRUNCATED>");
529                 offset = pi.captured_len;
530         } else {
531                 if (string_tree)
532                         proto_tree_add_text(string_tree,offset+0,4,
533                                 "length: %u", string_length);
534                 offset += 4;
535
536                 if (string_tree)
537                         proto_tree_add_text(string_tree,offset,string_length_copy,
538                                 "contents: %s", string_buffer_print);
539                 offset += string_length_copy;
540                 if (fill_length) {
541                         if (string_tree) {
542                                 if (fill_truncated) {
543                                         proto_tree_add_text(string_tree,
544                                         offset,fill_length_copy,
545                                         "fill bytes: opaque data<TRUNCATED>");
546                                 }
547                                 else {
548                                         proto_tree_add_text(string_tree,
549                                         offset,fill_length_copy,
550                                         "fill bytes: opaque data");
551                                 }
552                         }
553                         offset += fill_length_copy;
554                 }
555         }
556         
557         if (string_item) {
558                 proto_item_set_len(string_item, offset - old_offset);
559         }
560
561         if (string_buffer       != NULL) g_free (string_buffer      );
562         if (string_buffer_print != NULL) {
563                 if (string_buffer_ret != NULL)
564                         *string_buffer_ret = string_buffer_print;
565                 else
566                         g_free (string_buffer_print);
567         }
568         return offset;
569 }
570
571
572 int
573 dissect_rpc_string(const u_char *pd, int offset, frame_data *fd,
574     proto_tree *tree, int hfindex, char **string_buffer_ret)
575 {
576         offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, TRUE,
577             string_buffer_ret);
578
579         return offset;
580 }
581
582
583 int
584 dissect_rpc_data(const u_char *pd, int offset, frame_data *fd,
585     proto_tree *tree, int hfindex)
586 {
587         offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, FALSE,
588             NULL);
589
590         return offset;
591 }
592
593
594 void
595 dissect_rpc_auth( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
596 {
597         guint flavor;
598         guint length;
599         guint length_full;
600
601         /* both checks are made outside */
602         /* if (!BYTES_ARE_IN_FRAME(offset,8)) return; */
603         flavor = EXTRACT_UINT(pd,offset+0);
604         length = EXTRACT_UINT(pd,offset+4);
605         length_full = rpc_roundup(length);
606         /* if (!BYTES_ARE_IN_FRAME(offset+8,full_length)) return; */
607
608         if (tree) {
609                 proto_tree_add_item(tree, hf_rpc_auth_flavor, offset+0, 4,
610                         flavor);
611                 proto_tree_add_item(tree, hf_rpc_auth_length, offset+4, 4,
612                         length);
613         }
614
615         offset += 8;
616
617         switch (flavor) {
618                 case AUTH_UNIX: {
619                         guint stamp;
620                         guint uid;
621                         guint gid;
622                         guint gids_count;
623                         guint gids_i;
624                         guint gids_entry;
625                         proto_item *gitem;
626                         proto_tree *gtree = NULL;
627
628                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
629                         stamp = EXTRACT_UINT(pd,offset+0);
630                         if (tree)
631                                 proto_tree_add_item(tree, hf_rpc_auth_stamp,
632                                         offset+0, 4, stamp);
633                         offset += 4;
634
635                         offset = dissect_rpc_string(pd,offset,fd,
636                                 tree,hf_rpc_auth_machinename,NULL);
637
638                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
639                         uid = EXTRACT_UINT(pd,offset+0);
640                         if (tree)
641                                 proto_tree_add_item(tree, hf_rpc_auth_uid,
642                                         offset+0, 4, uid);
643                         offset += 4;
644
645                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
646                         gid = EXTRACT_UINT(pd,offset+0);
647                         if (tree)
648                                 proto_tree_add_item(tree, hf_rpc_auth_gid,
649                                         offset+0, 4, gid);
650                         offset += 4;
651
652                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
653                         gids_count = EXTRACT_UINT(pd,offset+0);
654                         if (tree) {
655                                 gitem = proto_tree_add_text(tree, offset, 4+gids_count*4,
656                                 "Auxiliary GIDs");
657                                 gtree = proto_item_add_subtree(gitem, ett_rpc_gids);
658                         }
659                         offset += 4;
660                         if (!BYTES_ARE_IN_FRAME(offset,4*gids_count)) return;
661                         for (gids_i = 0 ; gids_i < gids_count ; gids_i++) {
662                                 gids_entry = EXTRACT_UINT(pd,offset+0);
663                                 if (gtree)
664                                 proto_tree_add_item(gtree, hf_rpc_auth_gid,
665                                         offset, 4, gids_entry);
666                                 offset+=4;
667                         }
668                         /* how can I NOW change the gitem to print a list with
669                                 the first 16 gids? */
670                 }
671                 break;
672                 /*
673                 case AUTH_SHORT:
674
675                 break;
676                 */
677                 /* I have no tcpdump file with such a packet to verify the
678                         info from the RFC 1050 */
679                 /*
680                 case AUTH_DES:
681
682                 break;
683                 */
684                 default:
685                         if (length_full) {
686                                 if (tree)
687                                 proto_tree_add_text(tree,offset,
688                                 length_full, "opaque data");
689                         }
690         }
691 }
692
693 int
694 dissect_rpc_cred( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
695 {
696         guint length;
697         guint length_full;
698         proto_item *citem;
699         proto_tree *ctree;
700
701         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
702         length = EXTRACT_UINT(pd,offset+4);
703         length_full = rpc_roundup(length);
704         if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
705
706         if (tree) {
707                 citem = proto_tree_add_text(tree, offset, 8+length_full,
708                         "Credentials");
709                 ctree = proto_item_add_subtree(citem, ett_rpc_cred);
710                 dissect_rpc_auth(pd, offset, fd, ctree);
711         }
712         offset += 8 + length_full;
713
714         return offset;
715 }
716
717
718 int
719 dissect_rpc_verf( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
720 {
721         unsigned int length;
722         unsigned int length_full;
723         proto_item *vitem;
724         proto_tree *vtree;
725
726         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
727         length = EXTRACT_UINT(pd,offset+4);
728         length_full = rpc_roundup(length);
729         if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
730
731         if (tree) {
732                 vitem = proto_tree_add_text(tree, offset, 8+length_full,
733                         "Verifier");
734                 vtree = proto_item_add_subtree(vitem, ett_rpc_verf);
735                 dissect_rpc_auth(pd, offset, fd, vtree);
736         }
737         offset += 8 + length_full;
738
739         return offset;
740 }
741
742
743 gboolean
744 dissect_rpc( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
745 {
746         guint32 msg_type;
747         rpc_call_info rpc_key;
748         rpc_call_info *rpc_call = NULL;
749         rpc_prog_info_value *rpc_prog = NULL;
750         rpc_prog_info_key rpc_prog_key;
751
752         unsigned int xid;
753         unsigned int rpcvers;
754         unsigned int prog = 0;
755         unsigned int vers = 0;
756         unsigned int proc = 0;
757         int     proto = 0;
758         int     ett = 0;
759
760         unsigned int reply_state;
761         unsigned int accept_state;
762         unsigned int reject_state;
763
764         char *msg_type_name = NULL;
765         char *progname;
766         char *procname = NULL;
767         static char procname_static[20];
768
769         unsigned int vers_low;
770         unsigned int vers_high;
771
772         unsigned int auth_state;
773
774         proto_item *rpc_item=NULL;
775         proto_tree *rpc_tree = NULL;
776
777         proto_item *pitem=NULL;
778         proto_tree *ptree = NULL;
779         int offset_old = offset;
780
781         int use_rm = 0;
782         guint32 rpc_rm = 0;
783
784         rpc_call_info   rpc_call_msg;
785         rpc_proc_info_key       key;
786         rpc_proc_info_value     *value = NULL;
787         conversation_t* conversation;
788         static address null_address = { AT_NONE, 0, NULL };
789
790         dissect_function_t *dissect_function = NULL;
791
792         /* TCP uses record marking */
793         use_rm = (pi.ptype == PT_TCP);
794
795         /* the first 4 bytes are special in "record marking  mode" */
796         if (use_rm) {
797                 if (!BYTES_ARE_IN_FRAME(offset,4))
798                         return FALSE;
799                 rpc_rm = EXTRACT_UINT(pd,offset);
800                 offset += 4;
801         }
802
803         /*
804          * Check to see whether this looks like an RPC call or reply.
805          */
806         if (!BYTES_ARE_IN_FRAME(offset,8)) {
807                 /* Captured data in packet isn't enough to let us tell. */
808                 return FALSE;
809         }
810
811         /* both directions need at least this */
812         msg_type = EXTRACT_UINT(pd,offset+4);
813
814         switch (msg_type) {
815
816         case RPC_CALL:
817                 /* check for RPC call */
818                 if (!BYTES_ARE_IN_FRAME(offset,16)) {
819                         /* Captured data in packet isn't enough to let us
820                            tell. */
821                         return FALSE;
822                 }
823
824                 /* XID can be anything, we don't check it.
825                    We already have the message type.
826                    Check whether an RPC version number of 2 is in the
827                    location where it would be, and that an RPC program
828                    number we know about is in the locaton where it would be. */
829                 rpc_prog_key.prog = EXTRACT_UINT(pd,offset+12);
830                 if (EXTRACT_UINT(pd,offset+8) != 2 ||
831                     ((rpc_prog = g_hash_table_lookup(rpc_progs, &rpc_prog_key))
832                        == NULL)) {
833                         /* They're not, so it's probably not an RPC call. */
834                         return FALSE;
835                 }
836                 break;
837
838         case RPC_REPLY:
839                 /* Check for RPC reply.  A reply must match a call that
840                    we've seen, and the reply must be sent to the same
841                    port and address that the call came from, and must
842                    come from the port to which the call was sent.  (We
843                    don't worry about the address to which the call was
844                    sent and from which the reply was sent, because there's
845                    no guarantee that the reply will come from the address
846                    to which the call was sent.) */
847                 conversation = find_conversation(&null_address, &pi.dst,
848                     pi.ptype, pi.srcport, pi.destport);
849                 if (conversation == NULL) {
850                         /* We haven't seen an RPC call for that conversation,
851                            so we can't check for a reply to that call. */
852                         return FALSE;
853                 }
854
855                 /* The XIDs of the call and reply must match. */
856                 rpc_key.xid = EXTRACT_UINT(pd,offset+0);
857                 rpc_key.conversation = conversation;
858                 if ((rpc_call = rpc_call_lookup(&rpc_key)) == NULL) {
859                         /* The XID doesn't match a call from that
860                            conversation, so it's probably not an RPC reply. */
861                         return FALSE;
862                 }
863                 break;
864
865         default:
866                 /* The putative message type field contains neither
867                    RPC_CALL nor RPC_REPLY, so it's not an RPC call or
868                    reply. */
869                 return FALSE;
870         }
871
872         if (check_col(fd, COL_PROTOCOL))
873                 col_add_str(fd, COL_PROTOCOL, "RPC");
874
875         if (tree) {
876                 rpc_item = proto_tree_add_item(tree, proto_rpc, offset, END_OF_FRAME, NULL);
877                 if (rpc_item) {
878                         rpc_tree = proto_item_add_subtree(rpc_item, ett_rpc);
879                 }
880         }
881
882         if (use_rm && rpc_tree) {
883                 proto_tree_add_item(rpc_tree,hf_rpc_lastfrag,
884                         offset-4, 4, (rpc_rm >> 31) & 0x1);
885                 proto_tree_add_item(rpc_tree,hf_rpc_fraglen,
886                         offset-4, 4, rpc_rm & RPC_RM_FRAGLEN);
887         }
888
889         xid      = EXTRACT_UINT(pd,offset+0);
890         if (rpc_tree) {
891                 proto_tree_add_item_format(rpc_tree,hf_rpc_xid,
892                         offset+0, 4, xid, "XID: 0x%x (%u)", xid, xid);
893         }
894
895         msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u");
896         if (rpc_tree) {
897                 proto_tree_add_item(rpc_tree, hf_rpc_msgtype,
898                         offset+4, 4, msg_type);
899         }
900
901         offset += 8;
902
903         if (msg_type==RPC_CALL) {
904                 /* we know already the proto-entry, the ETT-const,
905                    and "rpc_prog" */
906                 proto = rpc_prog->proto;
907                 ett = rpc_prog->ett;
908                 progname = rpc_prog->progname;
909
910                 rpcvers = EXTRACT_UINT(pd,offset+0);
911                 if (rpc_tree) {
912                         proto_tree_add_item(rpc_tree,
913                                 hf_rpc_version, offset+0, 4, rpcvers);
914                 }
915
916                 prog = EXTRACT_UINT(pd,offset+4);
917                 
918                 if (rpc_tree) {
919                         proto_tree_add_item_format(rpc_tree,
920                                 hf_rpc_program, offset+4, 4, prog,
921                                 "Program: %s (%u)", progname, prog);
922                 }
923                 
924                 if (check_col(fd, COL_PROTOCOL)) {
925                         /* Set the protocol name to the underlying
926                            program name. */
927                         col_add_fstr(fd, COL_PROTOCOL, "%s", progname);
928                 }
929
930                 if (!BYTES_ARE_IN_FRAME(offset+8,4))
931                         return TRUE;
932                 vers = EXTRACT_UINT(pd,offset+8);
933                 if (rpc_tree) {
934                         proto_tree_add_item(rpc_tree,
935                                 hf_rpc_programversion, offset+8, 4, vers);
936                 }
937
938                 if (!BYTES_ARE_IN_FRAME(offset+12,4))
939                         return TRUE;
940                 proc = EXTRACT_UINT(pd,offset+12);
941
942                 key.prog = prog;
943                 key.vers = vers;
944                 key.proc = proc;
945
946                 value = g_hash_table_lookup(rpc_procs,&key);
947                 if (value != NULL) {
948                         dissect_function = value->dissect_call;
949                         procname = value->name;
950                 }
951                 else {
952                         /* happens only with strange program versions or
953                            non-existing dissectors */
954                         dissect_function = NULL;
955                         sprintf(procname_static, "proc-%u", proc);
956                         procname = procname_static;
957                 }
958                 if (rpc_tree) {
959                         proto_tree_add_item_format(rpc_tree,
960                                 hf_rpc_procedure, offset+12, 4, proc,
961                                 "Procedure: %s (%u)", procname, proc);
962                 }
963
964                 if (check_col(fd, COL_INFO)) {
965                         col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
966                                 vers,
967                                 procname,
968                                 msg_type_name,
969                                 xid);
970                 }
971
972                 /* Keep track of the address and port whence the call came,
973                    and the port to which the call is being sent, so that
974                    we can match up calls wityh replies.  (We don't worry
975                    about the address to which the call was sent and from
976                    which the reply was sent, because there's no
977                    guarantee that the reply will come from the address
978                    to which the call was sent.) */
979                 conversation = find_conversation(&pi.src, &null_address,
980                     pi.ptype, pi.srcport, pi.destport);
981                 if (conversation == NULL) {
982                         /* It's not part of any conversation - create a new one. */
983                         conversation = conversation_new(&pi.src, &null_address,
984                             pi.ptype, pi.srcport, pi.destport, NULL);
985                 }
986
987                 /* prepare the key data */
988                 rpc_call_msg.xid = xid;
989                 rpc_call_msg.conversation = conversation;
990
991                 /* look up the request */
992                 if (rpc_call_lookup(&rpc_call_msg)) {
993                         /* duplicate request */
994                         if (check_col(fd, COL_INFO)) {
995                                 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
996                                 if (rpc_tree) {
997                                         proto_tree_add_item_hidden(rpc_tree,
998                                                 hf_rpc_dup, 0,0, xid);
999                                         proto_tree_add_item_hidden(rpc_tree,
1000                                                 hf_rpc_call_dup, 0,0, xid);
1001                                 }
1002                         }
1003                 }
1004                 else {
1005                         /* prepare the value data */
1006                         rpc_call_msg.replies = 0;
1007                         rpc_call_msg.prog = prog;
1008                         rpc_call_msg.vers = vers;
1009                         rpc_call_msg.proc = proc;
1010                         rpc_call_msg.proc_info = value;
1011                         /* store it */
1012                         rpc_call_insert(&rpc_call_msg);
1013                 }
1014
1015                 offset += 16;
1016
1017                 offset = dissect_rpc_cred(pd, offset, fd, rpc_tree);
1018                 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1019
1020                 /* go to the next dissector */
1021                 /* goto dissect_rpc_prog; */
1022
1023         } /* end of RPC call */
1024         else if (msg_type == RPC_REPLY)
1025         {
1026                 /* we know already the type from the calling routine,
1027                    and we already have "rpc_call" set above. */
1028                 prog = rpc_call->prog;
1029                 vers = rpc_call->vers;
1030                 proc = rpc_call->proc;
1031                 if (rpc_call->proc_info != NULL) {
1032                         dissect_function = rpc_call->proc_info->dissect_reply;
1033                         if (rpc_call->proc_info->name != NULL) {
1034                                 procname = rpc_call->proc_info->name;
1035                         }
1036                         else {
1037                                 sprintf(procname_static, "proc-%u", proc);
1038                                 procname = procname_static;
1039                         }
1040                 }
1041                 else {
1042                         dissect_function = NULL;
1043                         sprintf(procname_static, "proc-%u", proc);
1044                         procname = procname_static;
1045                 }
1046                 rpc_call->replies++;
1047
1048                 rpc_prog_key.prog = prog;
1049                 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
1050                         proto = 0;
1051                         ett = 0;
1052                         progname = "Unknown";
1053                 }
1054                 else {
1055                         proto = rpc_prog->proto;
1056                         ett = rpc_prog->ett;
1057                         progname = rpc_prog->progname;
1058
1059                         if (check_col(fd, COL_PROTOCOL)) {
1060                                 /* Set the protocol name to the underlying
1061                                    program name. */
1062                                 col_add_fstr(fd, COL_PROTOCOL, "%s",
1063                                     progname);
1064                         }
1065                 }
1066
1067                 if (check_col(fd, COL_INFO)) {
1068                         col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
1069                                 vers,
1070                                 procname,
1071                                 msg_type_name,
1072                                 xid);
1073                 }
1074
1075                 if (rpc_tree) {
1076                         proto_tree_add_item_format(rpc_tree,
1077                                 hf_rpc_program, 0, 0, prog,
1078                                 "Program: %s (%u)", progname, prog);
1079                         proto_tree_add_item(rpc_tree,
1080                                 hf_rpc_programversion, 0, 0, vers);
1081                         proto_tree_add_item_format(rpc_tree,
1082                                 hf_rpc_procedure, 0, 0, proc,
1083                                 "Procedure: %s (%u)", procname, proc);
1084                 }
1085
1086                 if (rpc_call->replies>1) {
1087                         if (check_col(fd, COL_INFO)) {
1088                                 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
1089                                 if (rpc_tree) {
1090                                         proto_tree_add_item_hidden(rpc_tree,
1091                                                 hf_rpc_dup, 0,0, xid);
1092                                         proto_tree_add_item_hidden(rpc_tree,
1093                                                 hf_rpc_reply_dup, 0,0, xid);
1094                                 }
1095                         }
1096                 }
1097
1098                 if (!BYTES_ARE_IN_FRAME(offset,4))
1099                         return TRUE;
1100                 reply_state = EXTRACT_UINT(pd,offset+0);
1101                 if (rpc_tree) {
1102                         proto_tree_add_item(rpc_tree, hf_rpc_state_reply,
1103                                 offset+0, 4, reply_state);
1104                 }
1105                 offset += 4;
1106
1107                 if (reply_state == MSG_ACCEPTED) {
1108                         offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1109                         if (!BYTES_ARE_IN_FRAME(offset,4))
1110                                 return TRUE;
1111                         accept_state = EXTRACT_UINT(pd,offset+0);
1112                         if (rpc_tree) {
1113                                 proto_tree_add_item(rpc_tree, hf_rpc_state_accept,
1114                                         offset+0, 4, accept_state);
1115                         }
1116                         offset += 4;
1117                         switch (accept_state) {
1118                                 case SUCCESS:
1119                                         /* now goto the lower protocol */
1120                                         goto dissect_rpc_prog;
1121                                 break;
1122                                 case PROG_MISMATCH:
1123                                         if (!BYTES_ARE_IN_FRAME(offset,8))
1124                                                 return TRUE;
1125                                         vers_low = EXTRACT_UINT(pd,offset+0);
1126                                         vers_high = EXTRACT_UINT(pd,offset+4);
1127                                         if (rpc_tree) {
1128                                                 proto_tree_add_item(rpc_tree,
1129                                                         hf_rpc_programversion_min,
1130                                                         offset+0, 4, vers_low);
1131                                                 proto_tree_add_item(rpc_tree,
1132                                                         hf_rpc_programversion_max,
1133                                                         offset+4, 4, vers_high);
1134                                         }
1135                                         offset += 8;
1136                                 break;
1137                                 default:
1138                                         /* void */
1139                                 break;
1140                         }
1141                 } else if (reply_state == MSG_DENIED) {
1142                         if (!BYTES_ARE_IN_FRAME(offset,4))
1143                                 return TRUE;
1144                         reject_state = EXTRACT_UINT(pd,offset+0);
1145                         if (rpc_tree) {
1146                                 proto_tree_add_item(rpc_tree,
1147                                         hf_rpc_state_reject, offset+0, 4,
1148                                         reject_state);
1149                         }
1150                         offset += 4;
1151
1152                         if (reject_state==RPC_MISMATCH) {
1153                                 if (!BYTES_ARE_IN_FRAME(offset,8))
1154                                         return TRUE;
1155                                 vers_low = EXTRACT_UINT(pd,offset+0);
1156                                 vers_high = EXTRACT_UINT(pd,offset+4);
1157                                 if (rpc_tree) {
1158                                         proto_tree_add_item(rpc_tree,
1159                                                 hf_rpc_version_min,
1160                                                 offset+0, 4, vers_low);
1161                                         proto_tree_add_item(rpc_tree,
1162                                                 hf_rpc_version_max,
1163                                                 offset+4, 4, vers_high);
1164                                 }
1165                                 offset += 8;
1166                         } else if (reject_state==AUTH_ERROR) {
1167                                 if (!BYTES_ARE_IN_FRAME(offset,4))
1168                                         return TRUE;
1169                                 auth_state = EXTRACT_UINT(pd,offset+0);
1170                                 if (rpc_tree) {
1171                                         proto_tree_add_item(rpc_tree,
1172                                                 hf_rpc_state_auth, offset+0, 4,
1173                                                 auth_state);
1174                                 }
1175                                 offset += 4;
1176                         }
1177                 } 
1178         } /* end of RPC reply */
1179
1180 dissect_rpc_prog:
1181         /* I know, goto is evil but it works as it is. */
1182
1183         /* now we know, that RPC was shorter */
1184         if (rpc_item) {
1185                 proto_item_set_len(rpc_item, offset - offset_old);
1186         }
1187
1188         /* create here the program specific sub-tree */
1189         if (tree) {
1190                 pitem = proto_tree_add_item(tree, proto, offset, END_OF_FRAME);
1191                 if (pitem) {
1192                         ptree = proto_item_add_subtree(pitem, ett);
1193                 }
1194
1195                 if (ptree) {
1196                         proto_tree_add_item(ptree,
1197                                 hf_rpc_programversion, 0, 0, vers);
1198                         proto_tree_add_item_format(ptree,
1199                                 hf_rpc_procedure, 0, 0, proc,
1200                                 "Procedure: %s (%u)", procname, proc);
1201                 }
1202         }
1203
1204         /* call a specific dissection */
1205         if (dissect_function != NULL) {
1206                 offset = dissect_function(pd, offset, fd, ptree);
1207         }
1208
1209         /* dissect any remaining bytes (incomplete dissection) as pure data in
1210            the ptree */
1211         dissect_data(pd, offset, fd, ptree);
1212
1213         return TRUE;
1214 }
1215
1216
1217 /* Discard any state we've saved. */
1218 static void
1219 rpc_init_protocol(void)
1220 {
1221         memset(rpc_call_table, '\0', sizeof rpc_call_table);
1222         rpc_call_index = 0;
1223         rpc_call_firstfree = 0;
1224 }
1225
1226
1227 /* will be called once from register.c at startup time */
1228 void
1229 proto_register_rpc(void)
1230 {
1231         static hf_register_info hf[] = {
1232                 { &hf_rpc_lastfrag, {
1233                         "Last Fragment", "rpc.lastfrag", FT_BOOLEAN, BASE_NONE,
1234                         &yesno, 0, "Last Fragment" }},
1235                 { &hf_rpc_fraglen, {
1236                         "Fragment Length", "rpc.fraglen", FT_UINT32, BASE_DEC,
1237                         NULL, 0, "Fragment Length" }},
1238                 { &hf_rpc_xid, {
1239                         "XID", "rpc.xid", FT_UINT32, BASE_HEX,
1240                         NULL, 0, "XID" }},
1241                 { &hf_rpc_msgtype, {
1242                         "Message Type", "rpc.msgtyp", FT_UINT32, BASE_DEC,
1243                         VALS(rpc_msg_type), 0, "Message Type" }},
1244                 { &hf_rpc_state_reply, {
1245                         "Reply State", "rpc.replystat", FT_UINT32, BASE_DEC,
1246                         VALS(rpc_reply_state), 0, "Reply State" }},
1247                 { &hf_rpc_state_accept, {
1248                         "Accept State", "rpc.state_accept", FT_UINT32, BASE_DEC,
1249                         VALS(rpc_accept_state), 0, "Accept State" }},
1250                 { &hf_rpc_state_reject, {
1251                         "Reject State", "rpc.state_reject", FT_UINT32, BASE_DEC,
1252                         VALS(rpc_reject_state), 0, "Reject State" }},
1253                 { &hf_rpc_state_auth, {
1254                         "Auth State", "rpc.state_auth", FT_UINT32, BASE_DEC,
1255                         VALS(rpc_auth_state), 0, "Auth State" }},
1256                 { &hf_rpc_version, {
1257                         "RPC Version", "rpc.version", FT_UINT32, BASE_DEC,
1258                         NULL, 0, "RPC Version" }},
1259                 { &hf_rpc_version_min, {
1260                         "RPC Version (Minimum)", "rpc.version.min", FT_UINT32, 
1261                         BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1262                 { &hf_rpc_version_max, {
1263                         "RPC Version (Maximum)", "rpc.version.max", FT_UINT32, 
1264                         BASE_DEC, NULL, 0, "RPC Version (Maximum)" }},
1265                 { &hf_rpc_program, {
1266                         "Program", "rpc.program", FT_UINT32, BASE_DEC,
1267                         NULL, 0, "Program" }},
1268                 { &hf_rpc_programversion, {
1269                         "Program Version", "rpc.programversion", FT_UINT32, 
1270                         BASE_DEC, NULL, 0, "Program Version" }},
1271                 { &hf_rpc_programversion_min, {
1272                         "Program Version (Minimum)", "rpc.programversion.min", FT_UINT32, 
1273                         BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1274                 { &hf_rpc_programversion_max, {
1275                         "Program Version (Maximum)", "rpc.programversion.max", FT_UINT32, 
1276                         BASE_DEC, NULL, 0, "Program Version (Maximum)" }},
1277                 { &hf_rpc_procedure, {
1278                         "Procedure", "rpc.procedure", FT_UINT32, BASE_DEC,
1279                         NULL, 0, "Procedure" }},
1280                 { &hf_rpc_auth_flavor, {
1281                         "Flavor", "rpc.auth.flavor", FT_UINT32, BASE_DEC,
1282                         VALS(rpc_auth_flavor), 0, "Flavor" }},
1283                 { &hf_rpc_auth_length, {
1284                         "Length", "rpc.auth.length", FT_UINT32, BASE_DEC,
1285                         NULL, 0, "Length" }},
1286                 { &hf_rpc_auth_stamp, {
1287                         "Stamp", "rpc.auth.stamp", FT_UINT32, BASE_HEX,
1288                         NULL, 0, "Stamp" }},
1289                 { &hf_rpc_auth_uid, {
1290                         "UID", "rpc.auth.uid", FT_UINT32, BASE_DEC,
1291                         NULL, 0, "UID" }},
1292                 { &hf_rpc_auth_gid, {
1293                         "GID", "rpc.auth.gid", FT_UINT32, BASE_DEC,
1294                         NULL, 0, "GID" }},
1295                 { &hf_rpc_auth_machinename, {
1296                         "Machine Name", "rpc.auth.machinename", FT_STRING, 
1297                         BASE_DEC, NULL, 0, "Machine Name" }},
1298                 { &hf_rpc_dup, {
1299                         "Duplicate Transaction", "rpc.dup", FT_UINT32, BASE_DEC,
1300                         NULL, 0, "Duplicate Transaction" }},
1301                 { &hf_rpc_call_dup, {
1302                         "Duplicate Call", "rpc.call.dup", FT_UINT32, BASE_DEC,
1303                         NULL, 0, "Duplicate Call" }},
1304                 { &hf_rpc_reply_dup, {
1305                         "Duplicate Reply", "rpc.reply.dup", FT_UINT32, BASE_DEC,
1306                         NULL, 0, "Duplicate Reply" }}
1307         };
1308         static gint *ett[] = {
1309                 &ett_rpc,
1310                 &ett_rpc_string,
1311                 &ett_rpc_cred,
1312                 &ett_rpc_verf,
1313                 &ett_rpc_gids,
1314         };
1315
1316         proto_rpc = proto_register_protocol("Remote Procedure Call", "rpc");
1317         proto_register_field_array(proto_rpc, hf, array_length(hf));
1318         proto_register_subtree_array(ett, array_length(ett));
1319         register_init_routine(&rpc_init_protocol);
1320 }