3fa36dbf2d4da9f31cee0ea898491e7a009303ef
[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.25 2000/01/07 22:05:36 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 int
408 dissect_rpc_opaque_data(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hfindex, int string_data)
409 {
410         proto_item *string_item = NULL;
411         proto_tree *string_tree = NULL;
412         int old_offset = offset;
413
414         int length_truncated = 0;
415
416         int string_truncated = 0;
417         guint32 string_length = 0;
418         guint32 string_length_full;
419         guint32 string_length_packet;
420         guint32 string_length_copy = 0;
421
422         int fill_truncated = 0;
423         guint32 fill_length  = 0;
424         guint32 fill_length_packet  = 0;
425         guint32 fill_length_copy  = 0;
426
427         char *string_buffer = NULL;
428         char *string_buffer_print = NULL;
429
430         if (BYTES_ARE_IN_FRAME(offset,4)) {
431                 string_length = EXTRACT_UINT(pd,offset+0);
432                 string_length_full = rpc_roundup(string_length);
433                 string_length_packet = pi.captured_len - (offset + 4);
434                 if (string_length_packet < string_length) {
435                         /* truncated string */
436                         string_truncated = 1;
437                         string_length_copy = string_length_packet;
438                         fill_truncated = 2;
439                         fill_length = 0;
440                         fill_length_packet = 0;
441                         fill_length_copy = 0;
442                 }
443                 else {
444                         /* full string data */
445                         string_truncated = 0;
446                         string_length_copy = string_length;
447                         fill_length = string_length_full - string_length;
448                         fill_length_packet = pi.captured_len - (offset + 4 + string_length);
449                         if (fill_length_packet < fill_length) {
450                                 /* truncated fill bytes */
451                                 fill_length_copy = fill_length_packet;
452                                 fill_truncated = 1;
453                         }
454                         else {
455                                 /* full fill bytes */
456                                 fill_length_copy = fill_length;
457                                 fill_truncated = 0;
458                         }
459                 }
460                 string_buffer = (char*)g_malloc(string_length_copy + 
461                         (string_data ? 1 : 0));
462                 memcpy(string_buffer,pd+offset+4,string_length_copy);
463                 if (string_data)
464                         string_buffer[string_length_copy] = '\0';
465
466                 /* calculate a nice printable string */
467                 if (string_length) {
468                         if (string_length != string_length_copy) {
469                                 if (string_data) {
470                                         /* alloc maximum data area */
471                                         string_buffer_print = (char*)g_malloc(string_length_copy + 12 + 1);
472                                         /* copy over the data */
473                                         memcpy(string_buffer_print,string_buffer,string_length_copy);
474                                         /* append a 0 byte for sure printing */
475                                         string_buffer_print[string_length_copy] = '\0';
476                                         /* append <TRUNCATED> */
477                                         /* This way, we get the TRUNCATED even
478                                            in the case of totally wrong packets,
479                                            where \0 are inside the string.
480                                            TRUNCATED will appear at the
481                                            first \0 or at the end (where we 
482                                            put the securing \0).
483                                         */
484                                         strcat(string_buffer_print,"<TRUNCATED>");
485                                 }
486                                 else {
487                                         string_buffer_print = g_strdup("<DATA><TRUNCATED>");
488                                 }
489                         }
490                         else {
491                                 if (string_data) {
492                                         string_buffer_print = g_strdup(string_buffer);
493                                 }
494                                 else {
495                                         string_buffer_print = g_strdup("<DATA>");
496                                 }
497                         }
498                 }
499                 else {
500                         string_buffer_print = g_strdup("<EMPTY>");
501                 }
502         }
503         else {
504                 length_truncated = 1;
505                 string_truncated = 2;
506                 fill_truncated = 2;
507                 string_buffer = g_strdup("");
508                 string_buffer_print = g_strdup("<TRUNCATED>");
509         }
510
511         if (tree) {
512                 string_item = proto_tree_add_text(tree,offset+0, END_OF_FRAME,
513                         "%s: %s", proto_registrar_get_name(hfindex), string_buffer_print);
514                 if (string_data) {
515                         proto_tree_add_item_hidden(tree, hfindex, offset+4,
516                                 string_length_copy, string_buffer);
517                 }
518                 if (string_item) {
519                         string_tree = proto_item_add_subtree(string_item, ett_rpc_string);
520                 }
521         }
522         if (length_truncated) {
523                 if (string_tree)
524                         proto_tree_add_text(string_tree,
525                                 offset,pi.captured_len-offset,
526                                 "length: <TRUNCATED>");
527                 offset = pi.captured_len;
528         } else {
529                 if (string_tree)
530                         proto_tree_add_text(string_tree,offset+0,4,
531                                 "length: %u", string_length);
532                 offset += 4;
533
534                 if (string_tree)
535                         proto_tree_add_text(string_tree,offset,string_length_copy,
536                                 "contents: %s", string_buffer_print);
537                 offset += string_length_copy;
538                 if (fill_length) {
539                         if (string_tree) {
540                                 if (fill_truncated) {
541                                         proto_tree_add_text(string_tree,
542                                         offset,fill_length_copy,
543                                         "fill bytes: opaque data<TRUNCATED>");
544                                 }
545                                 else {
546                                         proto_tree_add_text(string_tree,
547                                         offset,fill_length_copy,
548                                         "fill bytes: opaque data");
549                                 }
550                         }
551                         offset += fill_length_copy;
552                 }
553         }
554         
555         if (string_item) {
556                 proto_item_set_len(string_item, offset - old_offset);
557         }
558
559         if (string_buffer       != NULL) g_free (string_buffer      );
560         if (string_buffer_print != NULL) g_free (string_buffer_print);
561         return offset;
562 }
563
564
565 int
566 dissect_rpc_string(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hfindex)
567 {
568         offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, 1);
569
570         return offset;
571 }
572
573
574 int
575 dissect_rpc_data(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hfindex)
576 {
577         offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, 0);
578
579         return offset;
580 }
581
582
583 void
584 dissect_rpc_auth( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
585 {
586         guint flavor;
587         guint length;
588         guint length_full;
589
590         /* both checks are made outside */
591         /* if (!BYTES_ARE_IN_FRAME(offset,8)) return; */
592         flavor = EXTRACT_UINT(pd,offset+0);
593         length = EXTRACT_UINT(pd,offset+4);
594         length_full = rpc_roundup(length);
595         /* if (!BYTES_ARE_IN_FRAME(offset+8,full_length)) return; */
596
597         if (tree) {
598                 proto_tree_add_item(tree, hf_rpc_auth_flavor, offset+0, 4,
599                         flavor);
600                 proto_tree_add_item(tree, hf_rpc_auth_length, offset+4, 4,
601                         length);
602         }
603
604         offset += 8;
605
606         switch (flavor) {
607                 case AUTH_UNIX: {
608                         guint stamp;
609                         guint uid;
610                         guint gid;
611                         guint gids_count;
612                         guint gids_i;
613                         guint gids_entry;
614                         proto_item *gitem;
615                         proto_tree *gtree = NULL;
616
617                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
618                         stamp = EXTRACT_UINT(pd,offset+0);
619                         if (tree)
620                                 proto_tree_add_item(tree, hf_rpc_auth_stamp,
621                                         offset+0, 4, stamp);
622                         offset += 4;
623
624                         offset = dissect_rpc_string(pd,offset,fd,
625                                 tree,hf_rpc_auth_machinename);
626
627                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
628                         uid = EXTRACT_UINT(pd,offset+0);
629                         if (tree)
630                                 proto_tree_add_item(tree, hf_rpc_auth_uid,
631                                         offset+0, 4, uid);
632                         offset += 4;
633
634                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
635                         gid = EXTRACT_UINT(pd,offset+0);
636                         if (tree)
637                                 proto_tree_add_item(tree, hf_rpc_auth_gid,
638                                         offset+0, 4, gid);
639                         offset += 4;
640
641                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
642                         gids_count = EXTRACT_UINT(pd,offset+0);
643                         if (tree) {
644                                 gitem = proto_tree_add_text(tree, offset, 4+gids_count*4,
645                                 "Auxiliary GIDs");
646                                 gtree = proto_item_add_subtree(gitem, ett_rpc_gids);
647                         }
648                         offset += 4;
649                         if (!BYTES_ARE_IN_FRAME(offset,4*gids_count)) return;
650                         for (gids_i = 0 ; gids_i < gids_count ; gids_i++) {
651                                 gids_entry = EXTRACT_UINT(pd,offset+0);
652                                 if (gtree)
653                                 proto_tree_add_item(gtree, hf_rpc_auth_gid,
654                                         offset, 4, gids_entry);
655                                 offset+=4;
656                         }
657                         /* how can I NOW change the gitem to print a list with
658                                 the first 16 gids? */
659                 }
660                 break;
661                 /*
662                 case AUTH_SHORT:
663
664                 break;
665                 */
666                 /* I have no tcpdump file with such a packet to verify the
667                         info from the RFC 1050 */
668                 /*
669                 case AUTH_DES:
670
671                 break;
672                 */
673                 default:
674                         if (length_full) {
675                                 if (tree)
676                                 proto_tree_add_text(tree,offset,
677                                 length_full, "opaque data");
678                         }
679         }
680 }
681
682 int
683 dissect_rpc_cred( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
684 {
685         guint length;
686         guint length_full;
687         proto_item *citem;
688         proto_tree *ctree;
689
690         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
691         length = EXTRACT_UINT(pd,offset+4);
692         length_full = rpc_roundup(length);
693         if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
694
695         if (tree) {
696                 citem = proto_tree_add_text(tree, offset, 8+length_full,
697                         "Credentials");
698                 ctree = proto_item_add_subtree(citem, ett_rpc_cred);
699                 dissect_rpc_auth(pd, offset, fd, ctree);
700         }
701         offset += 8 + length_full;
702
703         return offset;
704 }
705
706
707 int
708 dissect_rpc_verf( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
709 {
710         unsigned int length;
711         unsigned int length_full;
712         proto_item *vitem;
713         proto_tree *vtree;
714
715         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
716         length = EXTRACT_UINT(pd,offset+4);
717         length_full = rpc_roundup(length);
718         if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
719
720         if (tree) {
721                 vitem = proto_tree_add_text(tree, offset, 8+length_full,
722                         "Verifier");
723                 vtree = proto_item_add_subtree(vitem, ett_rpc_verf);
724                 dissect_rpc_auth(pd, offset, fd, vtree);
725         }
726         offset += 8 + length_full;
727
728         return offset;
729 }
730
731
732 gboolean
733 dissect_rpc( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
734 {
735         guint32 msg_type;
736         rpc_call_info rpc_key;
737         rpc_call_info *rpc_call = NULL;
738         rpc_prog_info_value *rpc_prog = NULL;
739         rpc_prog_info_key rpc_prog_key;
740
741         unsigned int xid;
742         unsigned int rpcvers;
743         unsigned int prog = 0;
744         unsigned int vers = 0;
745         unsigned int proc = 0;
746         int     proto = 0;
747         int     ett = 0;
748
749         unsigned int reply_state;
750         unsigned int accept_state;
751         unsigned int reject_state;
752
753         char *msg_type_name = NULL;
754         char *progname;
755         char *procname = NULL;
756         static char procname_static[20];
757
758         unsigned int vers_low;
759         unsigned int vers_high;
760
761         unsigned int auth_state;
762
763         proto_item *rpc_item=NULL;
764         proto_tree *rpc_tree = NULL;
765
766         proto_item *pitem=NULL;
767         proto_tree *ptree = NULL;
768         int offset_old = offset;
769
770         int use_rm = 0;
771         guint32 rpc_rm = 0;
772
773         rpc_call_info   rpc_call_msg;
774         rpc_proc_info_key       key;
775         rpc_proc_info_value     *value = NULL;
776         conversation_t* conversation;
777         static address null_address = { AT_NONE, 0, NULL };
778
779         dissect_function_t *dissect_function = NULL;
780
781         /* TCP uses record marking */
782         use_rm = (pi.ptype == PT_TCP);
783
784         /* the first 4 bytes are special in "record marking  mode" */
785         if (use_rm) {
786                 if (!BYTES_ARE_IN_FRAME(offset,4))
787                         return FALSE;
788                 rpc_rm = EXTRACT_UINT(pd,offset);
789                 offset += 4;
790         }
791
792         /*
793          * Check to see whether this looks like an RPC call or reply.
794          */
795         if (!BYTES_ARE_IN_FRAME(offset,8)) {
796                 /* Captured data in packet isn't enough to let us tell. */
797                 return FALSE;
798         }
799
800         /* both directions need at least this */
801         msg_type = EXTRACT_UINT(pd,offset+4);
802
803         switch (msg_type) {
804
805         case RPC_CALL:
806                 /* check for RPC call */
807                 if (!BYTES_ARE_IN_FRAME(offset,16)) {
808                         /* Captured data in packet isn't enough to let us
809                            tell. */
810                         return FALSE;
811                 }
812
813                 /* XID can be anything, we don't check it.
814                    We already have the message type.
815                    Check whether an RPC version number of 2 is in the
816                    location where it would be, and that an RPC program
817                    number we know about is in the locaton where it would be. */
818                 rpc_prog_key.prog = EXTRACT_UINT(pd,offset+12);
819                 if (EXTRACT_UINT(pd,offset+8) != 2 ||
820                     ((rpc_prog = g_hash_table_lookup(rpc_progs, &rpc_prog_key))
821                        == NULL)) {
822                         /* They're not, so it's probably not an RPC call. */
823                         return FALSE;
824                 }
825                 break;
826
827         case RPC_REPLY:
828                 /* Check for RPC reply.  A reply must match a call that
829                    we've seen, and the reply must be sent to the same
830                    port and address that the call came from, and must
831                    come from the port to which the call was sent.  (We
832                    don't worry about the address to which the call was
833                    sent and from which the reply was sent, because there's
834                    no guarantee that the reply will come from the address
835                    to which the call was sent.) */
836                 conversation = find_conversation(&null_address, &pi.dst,
837                     pi.ptype, pi.srcport, pi.destport);
838                 if (conversation == NULL) {
839                         /* We haven't seen an RPC call for that conversation,
840                            so we can't check for a reply to that call. */
841                         return FALSE;
842                 }
843
844                 /* The XIDs of the call and reply must match. */
845                 rpc_key.xid = EXTRACT_UINT(pd,offset+0);
846                 rpc_key.conversation = conversation;
847                 if ((rpc_call = rpc_call_lookup(&rpc_key)) == NULL) {
848                         /* The XID doesn't match a call from that
849                            conversation, so it's probably not an RPC reply. */
850                         return FALSE;
851                 }
852                 break;
853
854         default:
855                 /* The putative message type field contains neither
856                    RPC_CALL nor RPC_REPLY, so it's not an RPC call or
857                    reply. */
858                 return FALSE;
859         }
860
861         if (check_col(fd, COL_PROTOCOL))
862                 col_add_str(fd, COL_PROTOCOL, "RPC");
863
864         if (tree) {
865                 rpc_item = proto_tree_add_item(tree, proto_rpc, offset, END_OF_FRAME, NULL);
866                 if (rpc_item) {
867                         rpc_tree = proto_item_add_subtree(rpc_item, ett_rpc);
868                 }
869         }
870
871         if (use_rm && rpc_tree) {
872                 proto_tree_add_item(rpc_tree,hf_rpc_lastfrag,
873                         offset-4, 4, (rpc_rm >> 31) & 0x1);
874                 proto_tree_add_item(rpc_tree,hf_rpc_fraglen,
875                         offset-4, 4, rpc_rm & RPC_RM_FRAGLEN);
876         }
877
878         xid      = EXTRACT_UINT(pd,offset+0);
879         if (rpc_tree) {
880                 proto_tree_add_item_format(rpc_tree,hf_rpc_xid,
881                         offset+0, 4, xid, "XID: 0x%x (%u)", xid, xid);
882         }
883
884         msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u");
885         if (rpc_tree) {
886                 proto_tree_add_item(rpc_tree, hf_rpc_msgtype,
887                         offset+4, 4, msg_type);
888         }
889
890         offset += 8;
891
892         if (msg_type==RPC_CALL) {
893                 /* we know already the proto-entry, the ETT-const,
894                    and "rpc_prog" */
895                 proto = rpc_prog->proto;
896                 ett = rpc_prog->ett;
897                 progname = rpc_prog->progname;
898
899                 rpcvers = EXTRACT_UINT(pd,offset+0);
900                 if (rpc_tree) {
901                         proto_tree_add_item(rpc_tree,
902                                 hf_rpc_version, offset+0, 4, rpcvers);
903                 }
904
905                 prog = EXTRACT_UINT(pd,offset+4);
906                 
907                 if (rpc_tree) {
908                         proto_tree_add_item_format(rpc_tree,
909                                 hf_rpc_program, offset+4, 4, prog,
910                                 "Program: %s (%u)", progname, prog);
911                 }
912                 
913                 if (check_col(fd, COL_PROTOCOL)) {
914                         /* Set the protocol name to the underlying
915                            program name. */
916                         col_add_fstr(fd, COL_PROTOCOL, "%s", progname);
917                 }
918
919                 if (!BYTES_ARE_IN_FRAME(offset+8,4))
920                         return TRUE;
921                 vers = EXTRACT_UINT(pd,offset+8);
922                 if (rpc_tree) {
923                         proto_tree_add_item(rpc_tree,
924                                 hf_rpc_programversion, offset+8, 4, vers);
925                 }
926
927                 if (!BYTES_ARE_IN_FRAME(offset+12,4))
928                         return TRUE;
929                 proc = EXTRACT_UINT(pd,offset+12);
930
931                 key.prog = prog;
932                 key.vers = vers;
933                 key.proc = proc;
934
935                 value = g_hash_table_lookup(rpc_procs,&key);
936                 if (value != NULL) {
937                         dissect_function = value->dissect_call;
938                         procname = value->name;
939                 }
940                 else {
941                         /* happens only with strange program versions or
942                            non-existing dissectors */
943                         dissect_function = NULL;
944                         sprintf(procname_static, "proc-%u", proc);
945                         procname = procname_static;
946                 }
947                 if (rpc_tree) {
948                         proto_tree_add_item_format(rpc_tree,
949                                 hf_rpc_procedure, offset+12, 4, proc,
950                                 "Procedure: %s (%u)", procname, proc);
951                 }
952
953                 if (check_col(fd, COL_INFO)) {
954                         col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
955                                 vers,
956                                 procname,
957                                 msg_type_name,
958                                 xid);
959                 }
960
961                 /* Keep track of the address and port whence the call came,
962                    and the port to which the call is being sent, so that
963                    we can match up calls wityh replies.  (We don't worry
964                    about the address to which the call was sent and from
965                    which the reply was sent, because there's no
966                    guarantee that the reply will come from the address
967                    to which the call was sent.) */
968                 conversation = find_conversation(&pi.src, &null_address,
969                     pi.ptype, pi.srcport, pi.destport);
970                 if (conversation == NULL) {
971                         /* It's not part of any conversation - create a new one. */
972                         conversation = conversation_new(&pi.src, &null_address,
973                             pi.ptype, pi.srcport, pi.destport, NULL);
974                 }
975
976                 /* prepare the key data */
977                 rpc_call_msg.xid = xid;
978                 rpc_call_msg.conversation = conversation;
979
980                 /* look up the request */
981                 if (rpc_call_lookup(&rpc_call_msg)) {
982                         /* duplicate request */
983                         if (check_col(fd, COL_INFO)) {
984                                 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
985                                 if (rpc_tree) {
986                                         proto_tree_add_item_hidden(rpc_tree,
987                                                 hf_rpc_dup, 0,0, xid);
988                                         proto_tree_add_item_hidden(rpc_tree,
989                                                 hf_rpc_call_dup, 0,0, xid);
990                                 }
991                         }
992                 }
993                 else {
994                         /* prepare the value data */
995                         rpc_call_msg.replies = 0;
996                         rpc_call_msg.prog = prog;
997                         rpc_call_msg.vers = vers;
998                         rpc_call_msg.proc = proc;
999                         rpc_call_msg.proc_info = value;
1000                         /* store it */
1001                         rpc_call_insert(&rpc_call_msg);
1002                 }
1003
1004                 offset += 16;
1005
1006                 offset = dissect_rpc_cred(pd, offset, fd, rpc_tree);
1007                 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1008
1009                 /* go to the next dissector */
1010                 /* goto dissect_rpc_prog; */
1011
1012         } /* end of RPC call */
1013         else if (msg_type == RPC_REPLY)
1014         {
1015                 /* we know already the type from the calling routine,
1016                    and we already have "rpc_call" set above. */
1017                 prog = rpc_call->prog;
1018                 vers = rpc_call->vers;
1019                 proc = rpc_call->proc;
1020                 if (rpc_call->proc_info != NULL) {
1021                         dissect_function = rpc_call->proc_info->dissect_reply;
1022                         if (rpc_call->proc_info->name != NULL) {
1023                                 procname = rpc_call->proc_info->name;
1024                         }
1025                         else {
1026                                 sprintf(procname_static, "proc-%u", proc);
1027                                 procname = procname_static;
1028                         }
1029                 }
1030                 else {
1031                         dissect_function = NULL;
1032                         sprintf(procname_static, "proc-%u", proc);
1033                         procname = procname_static;
1034                 }
1035                 rpc_call->replies++;
1036
1037                 rpc_prog_key.prog = prog;
1038                 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
1039                         proto = 0;
1040                         ett = 0;
1041                         progname = "Unknown";
1042                 }
1043                 else {
1044                         proto = rpc_prog->proto;
1045                         ett = rpc_prog->ett;
1046                         progname = rpc_prog->progname;
1047
1048                         if (check_col(fd, COL_PROTOCOL)) {
1049                                 /* Set the protocol name to the underlying
1050                                    program name. */
1051                                 col_add_fstr(fd, COL_PROTOCOL, "%s",
1052                                     progname);
1053                         }
1054                 }
1055
1056                 if (check_col(fd, COL_INFO)) {
1057                         col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
1058                                 vers,
1059                                 procname,
1060                                 msg_type_name,
1061                                 xid);
1062                 }
1063
1064                 if (rpc_tree) {
1065                         proto_tree_add_item_format(rpc_tree,
1066                                 hf_rpc_program, 0, 0, prog,
1067                                 "Program: %s (%u)", progname, prog);
1068                         proto_tree_add_item(rpc_tree,
1069                                 hf_rpc_programversion, 0, 0, vers);
1070                         proto_tree_add_item_format(rpc_tree,
1071                                 hf_rpc_procedure, 0, 0, proc,
1072                                 "Procedure: %s (%u)", procname, proc);
1073                 }
1074
1075                 if (rpc_call->replies>1) {
1076                         if (check_col(fd, COL_INFO)) {
1077                                 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
1078                                 if (rpc_tree) {
1079                                         proto_tree_add_item_hidden(rpc_tree,
1080                                                 hf_rpc_dup, 0,0, xid);
1081                                         proto_tree_add_item_hidden(rpc_tree,
1082                                                 hf_rpc_reply_dup, 0,0, xid);
1083                                 }
1084                         }
1085                 }
1086
1087                 if (!BYTES_ARE_IN_FRAME(offset,4))
1088                         return TRUE;
1089                 reply_state = EXTRACT_UINT(pd,offset+0);
1090                 if (rpc_tree) {
1091                         proto_tree_add_item(rpc_tree, hf_rpc_state_reply,
1092                                 offset+0, 4, reply_state);
1093                 }
1094                 offset += 4;
1095
1096                 if (reply_state == MSG_ACCEPTED) {
1097                         offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1098                         if (!BYTES_ARE_IN_FRAME(offset,4))
1099                                 return TRUE;
1100                         accept_state = EXTRACT_UINT(pd,offset+0);
1101                         if (rpc_tree) {
1102                                 proto_tree_add_item(rpc_tree, hf_rpc_state_accept,
1103                                         offset+0, 4, accept_state);
1104                         }
1105                         offset += 4;
1106                         switch (accept_state) {
1107                                 case SUCCESS:
1108                                         /* now goto the lower protocol */
1109                                         goto dissect_rpc_prog;
1110                                 break;
1111                                 case PROG_MISMATCH:
1112                                         if (!BYTES_ARE_IN_FRAME(offset,8))
1113                                                 return TRUE;
1114                                         vers_low = EXTRACT_UINT(pd,offset+0);
1115                                         vers_high = EXTRACT_UINT(pd,offset+4);
1116                                         if (rpc_tree) {
1117                                                 proto_tree_add_item(rpc_tree,
1118                                                         hf_rpc_programversion_min,
1119                                                         offset+0, 4, vers_low);
1120                                                 proto_tree_add_item(rpc_tree,
1121                                                         hf_rpc_programversion_max,
1122                                                         offset+4, 4, vers_high);
1123                                         }
1124                                         offset += 8;
1125                                 break;
1126                                 default:
1127                                         /* void */
1128                                 break;
1129                         }
1130                 } else if (reply_state == MSG_DENIED) {
1131                         if (!BYTES_ARE_IN_FRAME(offset,4))
1132                                 return TRUE;
1133                         reject_state = EXTRACT_UINT(pd,offset+0);
1134                         if (rpc_tree) {
1135                                 proto_tree_add_item(rpc_tree,
1136                                         hf_rpc_state_reject, offset+0, 4,
1137                                         reject_state);
1138                         }
1139                         offset += 4;
1140
1141                         if (reject_state==RPC_MISMATCH) {
1142                                 if (!BYTES_ARE_IN_FRAME(offset,8))
1143                                         return TRUE;
1144                                 vers_low = EXTRACT_UINT(pd,offset+0);
1145                                 vers_high = EXTRACT_UINT(pd,offset+4);
1146                                 if (rpc_tree) {
1147                                         proto_tree_add_item(rpc_tree,
1148                                                 hf_rpc_version_min,
1149                                                 offset+0, 4, vers_low);
1150                                         proto_tree_add_item(rpc_tree,
1151                                                 hf_rpc_version_max,
1152                                                 offset+4, 4, vers_high);
1153                                 }
1154                                 offset += 8;
1155                         } else if (reject_state==AUTH_ERROR) {
1156                                 if (!BYTES_ARE_IN_FRAME(offset,4))
1157                                         return TRUE;
1158                                 auth_state = EXTRACT_UINT(pd,offset+0);
1159                                 if (rpc_tree) {
1160                                         proto_tree_add_item(rpc_tree,
1161                                                 hf_rpc_state_auth, offset+0, 4,
1162                                                 auth_state);
1163                                 }
1164                                 offset += 4;
1165                         }
1166                 } 
1167         } /* end of RPC reply */
1168
1169 dissect_rpc_prog:
1170         /* I know, goto is evil but it works as it is. */
1171
1172         /* now we know, that RPC was shorter */
1173         if (rpc_item) {
1174                 proto_item_set_len(rpc_item, offset - offset_old);
1175         }
1176
1177         /* create here the program specific sub-tree */
1178         if (tree) {
1179                 pitem = proto_tree_add_item(tree, proto, offset, END_OF_FRAME);
1180                 if (pitem) {
1181                         ptree = proto_item_add_subtree(pitem, ett);
1182                 }
1183
1184                 if (ptree) {
1185                         proto_tree_add_item(ptree,
1186                                 hf_rpc_programversion, 0, 0, vers);
1187                         proto_tree_add_item_format(ptree,
1188                                 hf_rpc_procedure, 0, 0, proc,
1189                                 "Procedure: %s (%u)", procname, proc);
1190                 }
1191         }
1192
1193         /* call a specific dissection */
1194         if (dissect_function != NULL) {
1195                 offset = dissect_function(pd, offset, fd, ptree);
1196         }
1197
1198         /* dissect any remaining bytes (incomplete dissection) as pure data in
1199            the ptree */
1200         dissect_data(pd, offset, fd, ptree);
1201
1202         return TRUE;
1203 }
1204
1205
1206 /* Discard any state we've saved. */
1207 static void
1208 rpc_init_protocol(void)
1209 {
1210         memset(rpc_call_table, '\0', sizeof rpc_call_table);
1211         rpc_call_index = 0;
1212         rpc_call_firstfree = 0;
1213 }
1214
1215
1216 /* will be called once from register.c at startup time */
1217 void
1218 proto_register_rpc(void)
1219 {
1220         static hf_register_info hf[] = {
1221                 { &hf_rpc_lastfrag, {
1222                         "Last Fragment", "rpc.lastfrag", FT_BOOLEAN, BASE_NONE,
1223                         &yesno, 0, "Last Fragment" }},
1224                 { &hf_rpc_fraglen, {
1225                         "Fragment Length", "rpc.fraglen", FT_UINT32, BASE_DEC,
1226                         NULL, 0, "Fragment Length" }},
1227                 { &hf_rpc_xid, {
1228                         "XID", "rpc.xid", FT_UINT32, BASE_HEX,
1229                         NULL, 0, "XID" }},
1230                 { &hf_rpc_msgtype, {
1231                         "Message Type", "rpc.msgtyp", FT_UINT32, BASE_DEC,
1232                         VALS(rpc_msg_type), 0, "Message Type" }},
1233                 { &hf_rpc_state_reply, {
1234                         "Reply State", "rpc.replystat", FT_UINT32, BASE_DEC,
1235                         VALS(rpc_reply_state), 0, "Reply State" }},
1236                 { &hf_rpc_state_accept, {
1237                         "Accept State", "rpc.state_accept", FT_UINT32, BASE_DEC,
1238                         VALS(rpc_accept_state), 0, "Accept State" }},
1239                 { &hf_rpc_state_reject, {
1240                         "Reject State", "rpc.state_reject", FT_UINT32, BASE_DEC,
1241                         VALS(rpc_reject_state), 0, "Reject State" }},
1242                 { &hf_rpc_state_auth, {
1243                         "Auth State", "rpc.state_auth", FT_UINT32, BASE_DEC,
1244                         VALS(rpc_auth_state), 0, "Auth State" }},
1245                 { &hf_rpc_version, {
1246                         "RPC Version", "rpc.version", FT_UINT32, BASE_DEC,
1247                         NULL, 0, "RPC Version" }},
1248                 { &hf_rpc_version_min, {
1249                         "RPC Version (Minimum)", "rpc.version.min", FT_UINT32, 
1250                         BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1251                 { &hf_rpc_version_max, {
1252                         "RPC Version (Maximum)", "rpc.version.max", FT_UINT32, 
1253                         BASE_DEC, NULL, 0, "RPC Version (Maximum)" }},
1254                 { &hf_rpc_program, {
1255                         "Program", "rpc.program", FT_UINT32, BASE_DEC,
1256                         NULL, 0, "Program" }},
1257                 { &hf_rpc_programversion, {
1258                         "Program Version", "rpc.programversion", FT_UINT32, 
1259                         BASE_DEC, NULL, 0, "Program Version" }},
1260                 { &hf_rpc_programversion_min, {
1261                         "Program Version (Minimum)", "rpc.programversion.min", FT_UINT32, 
1262                         BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1263                 { &hf_rpc_programversion_max, {
1264                         "Program Version (Maximum)", "rpc.programversion.max", FT_UINT32, 
1265                         BASE_DEC, NULL, 0, "Program Version (Maximum)" }},
1266                 { &hf_rpc_procedure, {
1267                         "Procedure", "rpc.procedure", FT_UINT32, BASE_DEC,
1268                         NULL, 0, "Procedure" }},
1269                 { &hf_rpc_auth_flavor, {
1270                         "Flavor", "rpc.auth.flavor", FT_UINT32, BASE_DEC,
1271                         VALS(rpc_auth_flavor), 0, "Flavor" }},
1272                 { &hf_rpc_auth_length, {
1273                         "Length", "rpc.auth.length", FT_UINT32, BASE_DEC,
1274                         NULL, 0, "Length" }},
1275                 { &hf_rpc_auth_stamp, {
1276                         "Stamp", "rpc.auth.stamp", FT_UINT32, BASE_HEX,
1277                         NULL, 0, "Stamp" }},
1278                 { &hf_rpc_auth_uid, {
1279                         "UID", "rpc.auth.uid", FT_UINT32, BASE_DEC,
1280                         NULL, 0, "UID" }},
1281                 { &hf_rpc_auth_gid, {
1282                         "GID", "rpc.auth.gid", FT_UINT32, BASE_DEC,
1283                         NULL, 0, "GID" }},
1284                 { &hf_rpc_auth_machinename, {
1285                         "Machine Name", "rpc.auth.machinename", FT_STRING, 
1286                         BASE_DEC, NULL, 0, "Machine Name" }},
1287                 { &hf_rpc_dup, {
1288                         "Duplicate Transaction", "rpc.dup", FT_UINT32, BASE_DEC,
1289                         NULL, 0, "Duplicate Transaction" }},
1290                 { &hf_rpc_call_dup, {
1291                         "Duplicate Call", "rpc.call.dup", FT_UINT32, BASE_DEC,
1292                         NULL, 0, "Duplicate Call" }},
1293                 { &hf_rpc_reply_dup, {
1294                         "Duplicate Reply", "rpc.reply.dup", FT_UINT32, BASE_DEC,
1295                         NULL, 0, "Duplicate Reply" }}
1296         };
1297         static gint *ett[] = {
1298                 &ett_rpc,
1299                 &ett_rpc_string,
1300                 &ett_rpc_cred,
1301                 &ett_rpc_verf,
1302                 &ett_rpc_gids,
1303         };
1304
1305         proto_rpc = proto_register_protocol("Remote Procedure Call", "rpc");
1306         proto_register_field_array(proto_rpc, hf, array_length(hf));
1307         proto_register_subtree_array(ett, array_length(ett));
1308         register_init_routine(&rpc_init_protocol);
1309 }