Name updates to stuff in GSS authentication for ONC RPC, from Dug Song.
[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.40 2000/08/24 22:58:55 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[] = {
51         { RPC_CALL, "Call" },
52         { RPC_REPLY, "Reply" },
53         { 0, NULL }
54 };
55
56 static const value_string rpc_reply_state[] = {
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         { RPCSEC_GSS, "RPCSEC_GSS" },
68         { 0, NULL }
69 };
70
71 static const value_string rpc_authgss_proc[] = {
72         { RPCSEC_GSS_DATA, "RPCSEC_GSS_DATA" },
73         { RPCSEC_GSS_INIT, "RPCSEC_GSS_INIT" },
74         { RPCSEC_GSS_CONTINUE_INIT, "RPCSEC_GSS_CONTINUE_INIT" },
75         { RPCSEC_GSS_DESTROY, "RPCSEC_GSS_DESTROY" },
76         { 0, NULL }
77 };
78
79 static const value_string rpc_authgss_svc[] = {
80         { RPCSEC_GSS_SVC_NONE, "rpcsec_gss_svc_none" },
81         { RPCSEC_GSS_SVC_INTEGRITY, "rpcsec_gss_svc_integrity" },
82         { RPCSEC_GSS_SVC_PRIVACY, "rpcsec_gss_svc_privacy" },
83         { 0, NULL }
84 };
85
86 static const value_string rpc_accept_state[] = {
87         { SUCCESS, "RPC executed successfully" },
88         { PROG_UNAVAIL, "remote hasn't exported program" },
89         { PROG_MISMATCH, "remote can't support version #" },
90         { PROC_UNAVAIL, "program can't support procedure" },
91         { GARBAGE_ARGS, "procedure can't decode params" },
92         { 0, NULL }
93 };
94
95 static const value_string rpc_reject_state[] = {
96         { RPC_MISMATCH, "RPC_MISMATCH" },
97         { AUTH_ERROR, "AUTH_ERROR" },
98         { 0, NULL }
99 };
100
101 static const value_string rpc_auth_state[] = {
102         { AUTH_BADCRED, "bad credential (seal broken)" },
103         { AUTH_REJECTEDCRED, "client must begin new session" },
104         { AUTH_BADVERF, "bad verifier (seal broken)" },
105         { AUTH_REJECTEDVERF, "verifier expired or replayed" },
106         { AUTH_TOOWEAK, "rejected for security reasons" },
107         { RPCSEC_GSSCREDPROB, "GSS credential problem" },
108         { RPCSEC_GSSCTXPROB, "GSS context problem" },
109         { 0, NULL }
110 };
111
112
113 /* the protocol number */
114 static int proto_rpc = -1;
115 static int hf_rpc_lastfrag = -1;
116 static int hf_rpc_fraglen = -1;
117 static int hf_rpc_xid = -1;
118 static int hf_rpc_msgtype = -1;
119 static int hf_rpc_version = -1;
120 static int hf_rpc_version_min = -1;
121 static int hf_rpc_version_max = -1;
122 static int hf_rpc_program = -1;
123 static int hf_rpc_programversion = -1;
124 static int hf_rpc_programversion_min = -1;
125 static int hf_rpc_programversion_max = -1;
126 static int hf_rpc_procedure = -1;
127 static int hf_rpc_auth_flavor = -1;
128 static int hf_rpc_auth_length = -1;
129 static int hf_rpc_auth_machinename = -1;
130 static int hf_rpc_auth_stamp = -1;
131 static int hf_rpc_auth_uid = -1;
132 static int hf_rpc_auth_gid = -1;
133 static int hf_rpc_authgss_v = -1;
134 static int hf_rpc_authgss_proc = -1;
135 static int hf_rpc_authgss_seq = -1;
136 static int hf_rpc_authgss_svc = -1;
137 static int hf_rpc_authgss_ctx = -1;
138 static int hf_rpc_authgss_major = -1;
139 static int hf_rpc_authgss_minor = -1;
140 static int hf_rpc_authgss_window = -1;
141 static int hf_rpc_authgss_token = -1;
142 static int hf_rpc_authgss_data_length = -1;
143 static int hf_rpc_authgss_data = -1;
144 static int hf_rpc_authgss_checksum = -1;
145 static int hf_rpc_state_accept = -1;
146 static int hf_rpc_state_reply = -1;
147 static int hf_rpc_state_reject = -1;
148 static int hf_rpc_state_auth = -1;
149 static int hf_rpc_dup = -1;
150 static int hf_rpc_call_dup = -1;
151 static int hf_rpc_reply_dup = -1;
152 static int hf_rpc_value_follows = -1;
153
154 static gint ett_rpc = -1;
155 static gint ett_rpc_string = -1;
156 static gint ett_rpc_cred = -1;
157 static gint ett_rpc_verf = -1;
158 static gint ett_rpc_gids = -1;
159 static gint ett_rpc_gss_data = -1;
160
161 /* Hash table with info on RPC program numbers */
162 static GHashTable *rpc_progs;
163
164 /* Hash table with info on RPC procedure numbers */
165 static GHashTable *rpc_procs;
166
167
168 /***********************************/
169 /* Hash array with procedure names */
170 /***********************************/
171
172 /* compare 2 keys */
173 gint
174 rpc_proc_equal(gconstpointer k1, gconstpointer k2)
175 {
176         rpc_proc_info_key* key1 = (rpc_proc_info_key*) k1;
177         rpc_proc_info_key* key2 = (rpc_proc_info_key*) k2;
178
179         return ((key1->prog == key2->prog && 
180                 key1->vers == key2->vers &&
181                 key1->proc == key2->proc) ?
182         TRUE : FALSE);
183 }
184
185 /* calculate a hash key */
186 guint
187 rpc_proc_hash(gconstpointer k)
188 {
189         rpc_proc_info_key* key = (rpc_proc_info_key*) k;
190
191         return (key->prog ^ (key->vers<<16) ^ (key->proc<<24));
192 }
193
194
195 /* insert some entries */
196 void
197 rpc_init_proc_table(guint prog, guint vers, const vsff *proc_table)
198 {
199         const vsff *proc;
200
201         for (proc = proc_table ; proc->strptr!=NULL; proc++) {
202                 rpc_proc_info_key *key;
203                 rpc_proc_info_value *value;
204
205                 key = (rpc_proc_info_key *) g_malloc(sizeof(rpc_proc_info_key));
206                 key->prog = prog;
207                 key->vers = vers;
208                 key->proc = proc->value;
209
210                 value = (rpc_proc_info_value *) g_malloc(sizeof(rpc_proc_info_value));
211                 value->name = proc->strptr;
212                 value->dissect_call = proc->dissect_call;
213                 value->dissect_reply = proc->dissect_reply;
214
215                 g_hash_table_insert(rpc_procs,key,value);
216         }
217 }
218
219 /*----------------------------------------*/
220 /* end of Hash array with procedure names */
221 /*----------------------------------------*/
222
223
224 /*********************************/
225 /* Hash array with program names */
226 /*********************************/
227
228 /* compare 2 keys */
229 gint
230 rpc_prog_equal(gconstpointer k1, gconstpointer k2)
231 {
232         rpc_prog_info_key* key1 = (rpc_prog_info_key*) k1;
233         rpc_prog_info_key* key2 = (rpc_prog_info_key*) k2;
234
235         return ((key1->prog == key2->prog) ?
236         TRUE : FALSE);
237 }
238
239
240 /* calculate a hash key */
241 guint
242 rpc_prog_hash(gconstpointer k)
243 {
244         rpc_prog_info_key* key = (rpc_prog_info_key*) k;
245
246         return (key->prog);
247 }
248
249
250 void
251 rpc_init_prog(int proto, guint32 prog, int ett)
252 {
253         rpc_prog_info_key *key;
254         rpc_prog_info_value *value;
255         char *uc_progname = NULL, *lc_progname = NULL;
256
257         key = (rpc_prog_info_key *) g_malloc(sizeof(rpc_prog_info_key));
258         key->prog = prog;
259
260         value = (rpc_prog_info_value *) g_malloc(sizeof(rpc_prog_info_value));
261         value->proto = proto;
262         value->ett = ett;
263
264         lc_progname = proto_registrar_get_abbrev(proto);
265         if ( lc_progname )
266         {
267                 int i;
268                 uc_progname = strdup(lc_progname);
269                 for (i=0; i<strlen(uc_progname); i++)
270                 {
271                         uc_progname[i] = toupper(uc_progname[i]);
272                 }
273         }
274         value->progname = uc_progname;
275
276         g_hash_table_insert(rpc_progs,key,value);
277 }
278
279 /*      return the name associated with a previously registered program. This
280         should probably eventually be expanded to use the rpc YP/NIS map
281         so that it can give names for programs not handled by ethereal */
282 char *rpc_prog_name(guint32 prog)
283 {
284         char *progname = NULL;
285         rpc_prog_info_key       rpc_prog_key;
286         rpc_prog_info_value     *rpc_prog;
287
288         rpc_prog_key.prog = prog;
289         if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
290                 progname = "Unknown";
291         }
292         else {
293                 progname = rpc_prog->progname;
294         }
295         return progname;
296 }
297
298
299 /*--------------------------------------*/
300 /* end of Hash array with program names */
301 /*--------------------------------------*/
302
303 /* static array, first quick implementation, I'll switch over to GList soon */ 
304 typedef struct _rpc_call_info {
305         guint32 xid;
306         conversation_t *conversation;
307         guint32 req_num;        /* frame number of first request seen */
308         guint32 rep_num;        /* frame number of first reply seen */
309         guint32 prog;
310         guint32 vers;
311         guint32 proc;
312         guint32 flavor;
313         guint32 gss_proc;
314         guint32 gss_svc;
315         rpc_proc_info_value*    proc_info;
316 } rpc_call_info;
317
318 #define RPC_CALL_TABLE_LENGTH 1000
319
320 rpc_call_info rpc_call_table[RPC_CALL_TABLE_LENGTH];
321 guint32 rpc_call_index = 0;
322 guint32 rpc_call_firstfree = 0;
323
324 static void
325 rpc_call_insert(rpc_call_info *call)
326 {
327         /* some space left? */
328         if (rpc_call_firstfree<RPC_CALL_TABLE_LENGTH) {
329                 /* some space left */
330                 /* take the first free entry */
331                 rpc_call_index = rpc_call_firstfree;
332                 /* increase this limit */
333                 rpc_call_firstfree++;
334                 /* rpc_call_firstfree may now be RPC_CALL_TABLE_LENGTH */
335         }
336         else {
337                 /* no space left */
338                 /* the next entry, with wrap around */
339                 rpc_call_index = (rpc_call_index+1) % rpc_call_firstfree;
340         }
341                 
342         /* put the entry in */
343         memcpy(&rpc_call_table[rpc_call_index],call,sizeof(*call));
344         return;
345 }
346
347
348 static rpc_call_info*
349 rpc_call_lookup(rpc_call_info *call)
350 {
351         int i;
352
353         i = rpc_call_index;
354         do {
355                 if (
356                         rpc_call_table[i].xid == call->xid &&
357                         rpc_call_table[i].conversation == call->conversation
358                 ) {
359                         return &rpc_call_table[i];
360                 }
361                 if (rpc_call_firstfree) {
362                         /* decrement by one, go to rpc_call_firstfree-1 
363                            at the start of the list */
364                         i = (i-1+rpc_call_firstfree) % rpc_call_firstfree;
365                 }
366         } while (i!=rpc_call_index);
367         return NULL;
368 }
369
370
371 unsigned int
372 rpc_roundup(unsigned int a)
373 {
374         unsigned int mod = a % 4;
375         return a + ((mod)? 4-mod : 0);
376 }
377
378
379 int
380 dissect_rpc_bool(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
381 int hfindex)
382 {
383         guint32 value;
384
385         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
386         value = EXTRACT_UINT(pd, offset+0);
387         if (tree)
388                 proto_tree_add_boolean(tree, hfindex, NullTVB, offset, 4, value);
389         offset += 4;
390
391         return offset;
392 }
393
394
395 int
396 dissect_rpc_bool_tvb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
397 int hfindex, int offset)
398 {
399         if (tree)
400                 proto_tree_add_item(tree, hfindex, tvb, offset, 4, FALSE);
401         return offset + 4;
402 }
403
404
405 int
406 dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
407 char* name)
408 {
409         guint32 value;
410
411         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
412         value = EXTRACT_UINT(pd, offset+0);
413
414         if (tree) {
415                 proto_tree_add_text(tree, NullTVB, offset, 4,
416                 "%s: %u", name, value);
417         }
418
419         offset += 4;
420         return offset;
421 }
422
423
424 int
425 dissect_rpc_uint32_tvb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
426 int hfindex, int offset)
427 {
428         if (tree)
429                 proto_tree_add_item(tree, hfindex, tvb, offset, 4, FALSE);
430         return offset + 4;
431 }
432
433
434 int
435 dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
436 char* name)
437 {
438         guint32 value_low;
439         guint32 value_high;
440
441         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
442         value_high = EXTRACT_UINT(pd, offset+0);
443         value_low = EXTRACT_UINT(pd, offset+4);
444
445         if (tree) {
446                 if (value_high)
447                         proto_tree_add_text(tree, NullTVB, offset, 8,
448                                 "%s: 0x%x%08x", name, value_high, value_low);
449                 else
450                         proto_tree_add_text(tree, NullTVB, offset, 8,
451                                 "%s: %u", name, value_low);
452         }
453
454         offset += 8;
455         return offset;
456 }
457
458
459 int
460 dissect_rpc_uint64_tvb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
461 int hfindex, int offset)
462 {
463         guint32 value_low;
464         guint32 value_high;
465
466         value_high = tvb_get_ntohl(tvb, offset + 0);
467         value_low  = tvb_get_ntohl(tvb, offset + 4);
468
469         if (tree) {
470                 if (value_high)
471                         proto_tree_add_text(tree, tvb, offset, 8,
472                                 "%s: 0x%x%08x", proto_registrar_get_name(hfindex), value_high, value_low);
473                 else
474                         proto_tree_add_uint(tree, hfindex, tvb, offset, 8, value_low);
475         }
476
477         return offset + 8;
478 }
479
480
481 static int
482 dissect_rpc_opaque_data(const u_char *pd, int offset, frame_data *fd,
483     proto_tree *tree, int hfindex, gboolean string_data,
484     char **string_buffer_ret)
485 {
486         proto_item *string_item = NULL;
487         proto_tree *string_tree = NULL;
488         int old_offset = offset;
489
490         int length_truncated = 0;
491
492         int string_truncated = 0;
493         guint32 string_length = 0;
494         guint32 string_length_full;
495         guint32 string_length_packet;
496         guint32 string_length_copy = 0;
497
498         int fill_truncated = 0;
499         guint32 fill_length  = 0;
500         guint32 fill_length_packet  = 0;
501         guint32 fill_length_copy  = 0;
502
503         char *string_buffer = NULL;
504         char *string_buffer_print = NULL;
505
506         if (BYTES_ARE_IN_FRAME(offset,4)) {
507                 string_length = EXTRACT_UINT(pd,offset+0);
508                 string_length_full = rpc_roundup(string_length);
509                 string_length_packet = pi.captured_len - (offset + 4);
510                 if (string_length_packet < string_length) {
511                         /* truncated string */
512                         string_truncated = 1;
513                         string_length_copy = string_length_packet;
514                         fill_truncated = 2;
515                         fill_length = 0;
516                         fill_length_packet = 0;
517                         fill_length_copy = 0;
518                 }
519                 else {
520                         /* full string data */
521                         string_truncated = 0;
522                         string_length_copy = string_length;
523                         fill_length = string_length_full - string_length;
524                         fill_length_packet = pi.captured_len - (offset + 4 + string_length);
525                         if (fill_length_packet < fill_length) {
526                                 /* truncated fill bytes */
527                                 fill_length_copy = fill_length_packet;
528                                 fill_truncated = 1;
529                         }
530                         else {
531                                 /* full fill bytes */
532                                 fill_length_copy = fill_length;
533                                 fill_truncated = 0;
534                         }
535                 }
536                 string_buffer = (char*)g_malloc(string_length_copy + 
537                         (string_data ? 1 : 0));
538                 memcpy(string_buffer,pd+offset+4,string_length_copy);
539                 if (string_data)
540                         string_buffer[string_length_copy] = '\0';
541
542                 /* calculate a nice printable string */
543                 if (string_length) {
544                         if (string_length != string_length_copy) {
545                                 if (string_data) {
546                                         /* alloc maximum data area */
547                                         string_buffer_print = (char*)g_malloc(string_length_copy + 12 + 1);
548                                         /* copy over the data */
549                                         memcpy(string_buffer_print,string_buffer,string_length_copy);
550                                         /* append a 0 byte for sure printing */
551                                         string_buffer_print[string_length_copy] = '\0';
552                                         /* append <TRUNCATED> */
553                                         /* This way, we get the TRUNCATED even
554                                            in the case of totally wrong packets,
555                                            where \0 are inside the string.
556                                            TRUNCATED will appear at the
557                                            first \0 or at the end (where we 
558                                            put the securing \0).
559                                         */
560                                         strcat(string_buffer_print,"<TRUNCATED>");
561                                 }
562                                 else {
563                                         string_buffer_print = g_strdup("<DATA><TRUNCATED>");
564                                 }
565                         }
566                         else {
567                                 if (string_data) {
568                                         string_buffer_print = g_strdup(string_buffer);
569                                 }
570                                 else {
571                                         string_buffer_print = g_strdup("<DATA>");
572                                 }
573                         }
574                 }
575                 else {
576                         string_buffer_print = g_strdup("<EMPTY>");
577                 }
578         }
579         else {
580                 length_truncated = 1;
581                 string_truncated = 2;
582                 fill_truncated = 2;
583                 string_buffer = g_strdup("");
584                 string_buffer_print = g_strdup("<TRUNCATED>");
585         }
586
587         if (tree) {
588                 string_item = proto_tree_add_text(tree, NullTVB,offset+0, END_OF_FRAME,
589                         "%s: %s", proto_registrar_get_name(hfindex), string_buffer_print);
590                 if (string_data) {
591                         proto_tree_add_string_hidden(tree, hfindex, NullTVB, offset+4,
592                                 string_length_copy, string_buffer);
593                 }
594                 if (string_item) {
595                         string_tree = proto_item_add_subtree(string_item, ett_rpc_string);
596                 }
597         }
598         if (length_truncated) {
599                 if (string_tree)
600                         proto_tree_add_text(string_tree, NullTVB,
601                                 offset,pi.captured_len-offset,
602                                 "length: <TRUNCATED>");
603                 offset = pi.captured_len;
604         } else {
605                 if (string_tree)
606                         proto_tree_add_text(string_tree, NullTVB,offset+0,4,
607                                 "length: %u", string_length);
608                 offset += 4;
609
610                 if (string_tree)
611                         proto_tree_add_text(string_tree, NullTVB,offset,string_length_copy,
612                                 "contents: %s", string_buffer_print);
613                 offset += string_length_copy;
614                 if (fill_length) {
615                         if (string_tree) {
616                                 if (fill_truncated) {
617                                         proto_tree_add_text(string_tree, NullTVB,
618                                         offset,fill_length_copy,
619                                         "fill bytes: opaque data<TRUNCATED>");
620                                 }
621                                 else {
622                                         proto_tree_add_text(string_tree, NullTVB,
623                                         offset,fill_length_copy,
624                                         "fill bytes: opaque data");
625                                 }
626                         }
627                         offset += fill_length_copy;
628                 }
629         }
630         
631         if (string_item) {
632                 proto_item_set_len(string_item, offset - old_offset);
633         }
634
635         if (string_buffer       != NULL) g_free (string_buffer      );
636         if (string_buffer_print != NULL) {
637                 if (string_buffer_ret != NULL)
638                         *string_buffer_ret = string_buffer_print;
639                 else
640                         g_free (string_buffer_print);
641         }
642         return offset;
643 }
644
645
646 int
647 dissect_rpc_string(const u_char *pd, int offset, frame_data *fd,
648     proto_tree *tree, int hfindex, char **string_buffer_ret)
649 {
650         offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, TRUE,
651             string_buffer_ret);
652
653         return offset;
654 }
655
656
657 int
658 dissect_rpc_string_tvb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int hfindex, int offset, char **string_buffer_ret)
659 {
660         const guint8 *pd;
661         int compat_offset;
662         int compat_offset_new;
663
664         tvb_compat(tvb, &pd, &compat_offset);
665         compat_offset += offset;
666         
667         compat_offset_new = dissect_rpc_string(pd, compat_offset, pinfo->fd,
668                                 tree, hfindex, string_buffer_ret);
669         offset += (compat_offset_new - compat_offset);
670         return offset;
671 }
672
673
674 int
675 dissect_rpc_data(const u_char *pd, int offset, frame_data *fd,
676     proto_tree *tree, int hfindex)
677 {
678         offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, FALSE,
679             NULL);
680
681         return offset;
682 }
683
684
685 int
686 dissect_rpc_data_tvb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int hfindex, int offset)
687 {
688         const guint8 *pd;
689         int compat_offset;
690         int compat_offset_new;
691
692         tvb_compat(tvb, &pd, &compat_offset);
693         compat_offset += offset;
694         
695         compat_offset_new = dissect_rpc_data(pd, compat_offset, pinfo->fd,
696                                 tree, hfindex);
697         offset += (compat_offset_new - compat_offset);
698         return offset;
699 }
700
701
702 int
703 dissect_rpc_list(const u_char *pd, int offset, frame_data *fd,
704         proto_tree *tree, dissect_function_t *rpc_list_dissector)
705 {
706         guint32 value_follows;
707
708         while (1) {
709                 if (!BYTES_ARE_IN_FRAME(offset,4)) break;
710                 value_follows = EXTRACT_UINT(pd, offset+0);
711                 proto_tree_add_boolean(tree,hf_rpc_value_follows, NullTVB,
712                         offset+0, 4, value_follows);
713                 offset += 4;
714                 if (value_follows == 1) {
715                         offset = rpc_list_dissector(pd, offset, fd, tree);
716                 }
717                 else {
718                         break;
719                 }
720         }
721
722         return offset;
723 }
724
725 static int
726 dissect_rpc_authunix_cred(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
727 {
728         guint stamp;
729         guint uid;
730         guint gid;
731         guint gids_count;
732         guint gids_i;
733         guint gids_entry;
734         proto_item *gitem;
735         proto_tree *gtree = NULL;
736
737         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
738         stamp = EXTRACT_UINT(pd,offset+0);
739         if (tree)
740                 proto_tree_add_uint(tree, hf_rpc_auth_stamp, NullTVB,
741                         offset+0, 4, stamp);
742         offset += 4;
743
744         offset = dissect_rpc_string(pd,offset,fd,
745                 tree,hf_rpc_auth_machinename,NULL);
746
747         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
748         uid = EXTRACT_UINT(pd,offset+0);
749         if (tree)
750                 proto_tree_add_uint(tree, hf_rpc_auth_uid, NullTVB,
751                         offset+0, 4, uid);
752         offset += 4;
753
754         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
755         gid = EXTRACT_UINT(pd,offset+0);
756         if (tree)
757                 proto_tree_add_uint(tree, hf_rpc_auth_gid, NullTVB,
758                         offset+0, 4, gid);
759         offset += 4;
760
761         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
762         gids_count = EXTRACT_UINT(pd,offset+0);
763         if (tree) {
764                 gitem = proto_tree_add_text(tree, NullTVB, offset, 4+gids_count*4,
765                 "Auxiliary GIDs");
766                 gtree = proto_item_add_subtree(gitem, ett_rpc_gids);
767         }
768         offset += 4;
769         
770         if (!BYTES_ARE_IN_FRAME(offset,4*gids_count)) return offset;
771         for (gids_i = 0 ; gids_i < gids_count ; gids_i++) {
772                 gids_entry = EXTRACT_UINT(pd,offset+0);
773                 if (gtree)
774                 proto_tree_add_uint(gtree, hf_rpc_auth_gid, NullTVB,
775                         offset, 4, gids_entry);
776                 offset+=4;
777         }
778         /* how can I NOW change the gitem to print a list with
779                 the first 16 gids? */
780
781         return offset;
782 }
783
784 static int
785 dissect_rpc_authgss_cred(const u_char *pd, int offset,
786                          frame_data *fd, proto_tree *tree)
787 {
788         guint agc_v;
789         guint agc_proc;
790         guint agc_seq;
791         guint agc_svc;
792
793         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
794         agc_v = EXTRACT_UINT(pd, offset+0);
795         if (tree)
796                 proto_tree_add_uint(tree, hf_rpc_authgss_v,
797                                     NullTVB, offset+0, 4, agc_v);
798         offset += 4;
799         
800         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
801         agc_proc = EXTRACT_UINT(pd, offset+0);
802         if (tree)
803                 proto_tree_add_uint(tree, hf_rpc_authgss_proc,
804                                     NullTVB, offset+0, 4, agc_proc);
805         offset += 4;
806         
807         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
808         agc_seq = EXTRACT_UINT(pd, offset+0);
809         if (tree)
810                 proto_tree_add_uint(tree, hf_rpc_authgss_seq,
811                                     NullTVB, offset+0, 4, agc_seq);
812         offset += 4;
813         
814         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
815         agc_svc = EXTRACT_UINT(pd, offset+0);
816         if (tree)
817                 proto_tree_add_uint(tree, hf_rpc_authgss_svc,
818                                     NullTVB, offset+0, 4, agc_svc);
819         offset += 4;
820         
821         offset = dissect_rpc_data(pd,offset,fd,tree,
822                                   hf_rpc_authgss_ctx);
823         
824         return offset;
825 }
826
827 static int
828 dissect_rpc_cred( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
829 {
830         guint flavor;
831         guint length;
832
833         proto_item *citem;
834         proto_tree *ctree;
835
836         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
837         flavor = EXTRACT_UINT(pd,offset+0);
838         length = EXTRACT_UINT(pd,offset+4);
839         length = rpc_roundup(length);
840         if (!BYTES_ARE_IN_FRAME(offset+8,length)) return offset;
841
842         if (tree) {
843                 citem = proto_tree_add_text(tree, NullTVB, offset,
844                                             8+length, "Credentials");
845                 ctree = proto_item_add_subtree(citem, ett_rpc_cred);
846                 proto_tree_add_uint(ctree, hf_rpc_auth_flavor, NullTVB,
847                                     offset+0, 4, flavor);
848                 proto_tree_add_uint(ctree, hf_rpc_auth_length, NullTVB,
849                                     offset+4, 4, length);
850
851                 switch (flavor) {
852                 case AUTH_UNIX:
853                         dissect_rpc_authunix_cred(pd, offset+8, fd, ctree);
854                         break;
855                 /*
856                 case AUTH_SHORT:
857
858                 break;
859                 */
860                 /* I have no tcpdump file with such a packet to verify the
861                         info from the RFC 1050 */
862                 /*
863                 case AUTH_DES:
864
865                 break;
866                 */
867                 case RPCSEC_GSS:
868                         dissect_rpc_authgss_cred(pd, offset+8, fd, ctree);
869                         break;
870                 default:
871                         if (length)
872                                 proto_tree_add_text(ctree, NullTVB, offset+8,
873                                                     length,"opaque data");
874                         break;
875         }
876         }
877         offset += 8 + length;
878
879         return offset;
880 }
881
882 static int
883 dissect_rpc_verf( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
884 {
885         guint flavor;
886         guint length;
887         
888         proto_item *vitem;
889         proto_tree *vtree;
890
891         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
892         flavor = EXTRACT_UINT(pd,offset+0);
893         length = EXTRACT_UINT(pd,offset+4);
894         length = rpc_roundup(length);
895         if (!BYTES_ARE_IN_FRAME(offset+8,length)) return offset;
896
897         if (tree) {
898                 vitem = proto_tree_add_text(tree, NullTVB, offset,
899                                             8+length, "Verifier");
900                 vtree = proto_item_add_subtree(vitem, ett_rpc_verf);
901                 proto_tree_add_uint(vtree, hf_rpc_auth_flavor, NullTVB,
902                                     offset+0, 4, flavor);
903
904                 switch (flavor) {
905                 case AUTH_UNIX:
906                         proto_tree_add_uint(vtree, hf_rpc_auth_length, NullTVB,
907                                             offset+4, 4, length);
908                         dissect_rpc_authunix_cred(pd, offset+8, fd, vtree);
909                         break;
910                 case RPCSEC_GSS:
911                         dissect_rpc_data(pd, offset+4, fd, vtree,
912                                          hf_rpc_authgss_checksum);
913                         break;
914                 default:
915                         proto_tree_add_uint(vtree, hf_rpc_auth_length, NullTVB,
916                                             offset+4, 4, length);
917                         if (length)
918                                 proto_tree_add_text(vtree, NullTVB, offset+8,
919                                                     length, "opaque data");
920                         break;
921                 }
922         }
923         offset += 8 + length;
924
925         return offset;
926 }
927
928 static int
929 dissect_rpc_authgss_initarg(const u_char *pd, int offset,
930                             frame_data *fd, proto_tree *tree)
931 {
932         offset = dissect_rpc_data(pd, offset, fd, tree, hf_rpc_authgss_token);
933         return offset;
934 }
935
936 static int
937 dissect_rpc_authgss_initres(const u_char *pd, int offset,
938                             frame_data *fd, proto_tree *tree)
939 {
940         int major, minor, window;
941         
942         offset = dissect_rpc_data(pd, offset, fd, tree, hf_rpc_authgss_ctx);
943         
944         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
945         major = EXTRACT_UINT(pd,offset+0);
946         if (tree)
947                 proto_tree_add_uint(tree, hf_rpc_authgss_major, NullTVB,
948                                     offset+0, 4, major);
949         offset += 4;
950
951         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
952         minor = EXTRACT_UINT(pd,offset+0);
953         if (tree)
954                 proto_tree_add_uint(tree, hf_rpc_authgss_minor, NullTVB,
955                                     offset+0, 4, minor);
956         offset += 4;
957
958         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
959         window = EXTRACT_UINT(pd,offset+0);
960         if (tree)
961                 proto_tree_add_uint(tree, hf_rpc_authgss_window, NullTVB,
962                                     offset+0, 4, window);
963         offset += 4;
964
965         offset = dissect_rpc_data(pd, offset, fd, tree, hf_rpc_authgss_token);
966
967         return offset;
968 }
969
970 static int
971 dissect_rpc_authgss_integ_data(const u_char *pd, int offset,
972                                frame_data *fd, proto_tree *tree,
973                                dissect_function_t *dissect_function)
974 {
975         guint32 length, seq;
976         
977         proto_item *gitem;
978         proto_tree *gtree;
979
980         if (!BYTES_ARE_IN_FRAME(offset, 8)) return offset;
981         length = EXTRACT_UINT(pd, offset+0);
982         length = rpc_roundup(length);
983         seq = EXTRACT_UINT(pd,offset+4);
984
985         if (tree) {
986                 gitem = proto_tree_add_text(tree, NullTVB, offset,
987                                             4+length, "GSS Data");
988                 gtree = proto_item_add_subtree(gitem, ett_rpc_gss_data);
989                 proto_tree_add_uint(gtree, hf_rpc_authgss_data_length,
990                                     NullTVB, offset+0, 4, length);
991                 proto_tree_add_uint(gtree, hf_rpc_authgss_seq,
992                                     NullTVB, offset+4, 4, seq);
993                 if (dissect_function != NULL)
994                         offset = dissect_function(pd, offset, fd, gtree);
995         }
996         offset += 8 + length;
997         offset = dissect_rpc_data(pd, offset, fd, tree, hf_rpc_authgss_checksum);
998         return offset;
999 }
1000
1001 static int
1002 dissect_rpc_authgss_priv_data(const u_char *pd, int offset,
1003                          frame_data *fd, proto_tree *tree)
1004 {
1005         offset = dissect_rpc_data(pd, offset, fd, tree, hf_rpc_authgss_data);
1006         return offset;
1007 }
1008
1009 gboolean
1010 dissect_rpc( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1011 {
1012         guint32 msg_type;
1013         rpc_call_info rpc_key;
1014         rpc_call_info *rpc_call = NULL;
1015         rpc_prog_info_value *rpc_prog = NULL;
1016         rpc_prog_info_key rpc_prog_key;
1017
1018         unsigned int xid;
1019         unsigned int rpcvers;
1020         unsigned int prog = 0;
1021         unsigned int vers = 0;
1022         unsigned int proc = 0;
1023         unsigned int flavor = 0;
1024         unsigned int gss_proc = 0;
1025         unsigned int gss_svc = 0;
1026         int     proto = 0;
1027         int     ett = 0;
1028
1029         unsigned int reply_state;
1030         unsigned int accept_state;
1031         unsigned int reject_state;
1032
1033         char *msg_type_name = NULL;
1034         char *progname;
1035         char *procname = NULL;
1036         static char procname_static[20];
1037
1038         unsigned int vers_low;
1039         unsigned int vers_high;
1040
1041         unsigned int auth_state;
1042
1043         proto_item *rpc_item=NULL;
1044         proto_tree *rpc_tree = NULL;
1045
1046         proto_item *pitem=NULL;
1047         proto_tree *ptree = NULL;
1048         int offset_old = offset;
1049
1050         int use_rm = 0;
1051         guint32 rpc_rm = 0;
1052
1053         rpc_call_info   rpc_call_msg;
1054         rpc_proc_info_key       key;
1055         rpc_proc_info_value     *value = NULL;
1056         conversation_t* conversation;
1057         static address null_address = { AT_NONE, 0, NULL };
1058
1059         dissect_function_t *dissect_function = NULL;
1060
1061         if (!proto_is_protocol_enabled(proto_rpc))
1062           return FALSE;
1063
1064         /* TCP uses record marking */
1065         use_rm = (pi.ptype == PT_TCP);
1066
1067         /* the first 4 bytes are special in "record marking  mode" */
1068         if (use_rm) {
1069                 if (!BYTES_ARE_IN_FRAME(offset,4))
1070                         return FALSE;
1071                 rpc_rm = EXTRACT_UINT(pd,offset);
1072                 offset += 4;
1073         }
1074
1075         /*
1076          * Check to see whether this looks like an RPC call or reply.
1077          */
1078         if (!BYTES_ARE_IN_FRAME(offset,8)) {
1079                 /* Captured data in packet isn't enough to let us tell. */
1080                 return FALSE;
1081         }
1082
1083         /* both directions need at least this */
1084         msg_type = EXTRACT_UINT(pd,offset+4);
1085
1086         switch (msg_type) {
1087
1088         case RPC_CALL:
1089                 /* check for RPC call */
1090                 if (!BYTES_ARE_IN_FRAME(offset,16)) {
1091                         /* Captured data in packet isn't enough to let us
1092                            tell. */
1093                         return FALSE;
1094                 }
1095
1096                 /* XID can be anything, we don't check it.
1097                    We already have the message type.
1098                    Check whether an RPC version number of 2 is in the
1099                    location where it would be, and that an RPC program
1100                    number we know about is in the locaton where it would be. */
1101                 rpc_prog_key.prog = EXTRACT_UINT(pd,offset+12);
1102                 if (EXTRACT_UINT(pd,offset+8) != 2 ||
1103                     ((rpc_prog = g_hash_table_lookup(rpc_progs, &rpc_prog_key))
1104                        == NULL)) {
1105                         /* They're not, so it's probably not an RPC call. */
1106                         return FALSE;
1107                 }
1108                 break;
1109
1110         case RPC_REPLY:
1111                 /* Check for RPC reply.  A reply must match a call that
1112                    we've seen, and the reply must be sent to the same
1113                    port and address that the call came from, and must
1114                    come from the port to which the call was sent.  (We
1115                    don't worry about the address to which the call was
1116                    sent and from which the reply was sent, because there's
1117                    no guarantee that the reply will come from the address
1118                    to which the call was sent.) */
1119                 conversation = find_conversation(&null_address, &pi.dst,
1120                     pi.ptype, pi.srcport, pi.destport);
1121                 if (conversation == NULL) {
1122                         /* We haven't seen an RPC call for that conversation,
1123                            so we can't check for a reply to that call. */
1124                         return FALSE;
1125                 }
1126
1127                 /* The XIDs of the call and reply must match. */
1128                 rpc_key.xid = EXTRACT_UINT(pd,offset+0);
1129                 rpc_key.conversation = conversation;
1130                 if ((rpc_call = rpc_call_lookup(&rpc_key)) == NULL) {
1131                         /* The XID doesn't match a call from that
1132                            conversation, so it's probably not an RPC reply. */
1133                         return FALSE;
1134                 }
1135                 break;
1136
1137         default:
1138                 /* The putative message type field contains neither
1139                    RPC_CALL nor RPC_REPLY, so it's not an RPC call or
1140                    reply. */
1141                 return FALSE;
1142         }
1143
1144         if (check_col(fd, COL_PROTOCOL))
1145                 col_add_str(fd, COL_PROTOCOL, "RPC");
1146
1147         if (tree) {
1148                 rpc_item = proto_tree_add_item(tree, proto_rpc, NullTVB, offset, END_OF_FRAME, FALSE);
1149                 if (rpc_item) {
1150                         rpc_tree = proto_item_add_subtree(rpc_item, ett_rpc);
1151                 }
1152         }
1153
1154         if (use_rm && rpc_tree) {
1155                 proto_tree_add_boolean(rpc_tree,hf_rpc_lastfrag, NullTVB,
1156                         offset-4, 4, (rpc_rm >> 31) & 0x1);
1157                 proto_tree_add_uint(rpc_tree,hf_rpc_fraglen, NullTVB,
1158                         offset-4, 4, rpc_rm & RPC_RM_FRAGLEN);
1159         }
1160
1161         xid      = EXTRACT_UINT(pd,offset+0);
1162         if (rpc_tree) {
1163                 proto_tree_add_uint_format(rpc_tree,hf_rpc_xid, NullTVB,
1164                         offset+0, 4, xid, "XID: 0x%x (%u)", xid, xid);
1165         }
1166
1167         msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u");
1168         if (rpc_tree) {
1169                 proto_tree_add_uint(rpc_tree, hf_rpc_msgtype, NullTVB,
1170                         offset+4, 4, msg_type);
1171         }
1172
1173         offset += 8;
1174
1175         if (msg_type==RPC_CALL) {
1176                 /* we know already the proto-entry, the ETT-const,
1177                    and "rpc_prog" */
1178                 proto = rpc_prog->proto;
1179                 ett = rpc_prog->ett;
1180                 progname = rpc_prog->progname;
1181
1182                 rpcvers = EXTRACT_UINT(pd,offset+0);
1183                 if (rpc_tree) {
1184                         proto_tree_add_uint(rpc_tree,
1185                                 hf_rpc_version, NullTVB, offset+0, 4, rpcvers);
1186                 }
1187
1188                 prog = EXTRACT_UINT(pd,offset+4);
1189                 
1190                 if (rpc_tree) {
1191                         proto_tree_add_uint_format(rpc_tree,
1192                                 hf_rpc_program, NullTVB, offset+4, 4, prog,
1193                                 "Program: %s (%u)", progname, prog);
1194                 }
1195                 
1196                 if (check_col(fd, COL_PROTOCOL)) {
1197                         /* Set the protocol name to the underlying
1198                            program name. */
1199                         col_add_fstr(fd, COL_PROTOCOL, "%s", progname);
1200                 }
1201
1202                 if (!BYTES_ARE_IN_FRAME(offset+8,4))
1203                         return TRUE;
1204                 vers = EXTRACT_UINT(pd,offset+8);
1205                 if (rpc_tree) {
1206                         proto_tree_add_uint(rpc_tree,
1207                                 hf_rpc_programversion, NullTVB, offset+8, 4, vers);
1208                 }
1209
1210                 if (!BYTES_ARE_IN_FRAME(offset+12,4))
1211                         return TRUE;
1212                 proc = EXTRACT_UINT(pd,offset+12);
1213
1214                 /* Check for RPCSEC_GSS */
1215                 if (proc == 0 && BYTES_ARE_IN_FRAME(offset+16,28)) {
1216                         flavor = EXTRACT_UINT(pd, offset+16);
1217                         if (flavor == RPCSEC_GSS) {
1218                                 gss_proc = EXTRACT_UINT(pd, offset+28);
1219                                 gss_svc = EXTRACT_UINT(pd, offset+34);
1220                         }
1221                 }
1222                 key.prog = prog;
1223                 key.vers = vers;
1224                 key.proc = proc;
1225
1226                 if ((value = g_hash_table_lookup(rpc_procs,&key)) != NULL) {
1227                         dissect_function = value->dissect_call;
1228                         procname = value->name;
1229                 }
1230                 else {
1231                         /* happens only with strange program versions or
1232                            non-existing dissectors */
1233                         dissect_function = NULL;
1234                         sprintf(procname_static, "proc-%u", proc);
1235                         procname = procname_static;
1236                 }
1237                 
1238                 if (rpc_tree) {
1239                         proto_tree_add_uint_format(rpc_tree,
1240                                 hf_rpc_procedure, NullTVB, offset+12, 4, proc,
1241                                 "Procedure: %s (%u)", procname, proc);
1242                 }
1243
1244                 if (check_col(fd, COL_INFO)) {
1245                         col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
1246                                 vers,
1247                                 procname,
1248                                 msg_type_name,
1249                                 xid);
1250                 }
1251
1252                 /* Keep track of the address and port whence the call came,
1253                    and the port to which the call is being sent, so that
1254                    we can match up calls wityh replies.  (We don't worry
1255                    about the address to which the call was sent and from
1256                    which the reply was sent, because there's no
1257                    guarantee that the reply will come from the address
1258                    to which the call was sent.) */
1259                 conversation = find_conversation(&pi.src, &null_address,
1260                     pi.ptype, pi.srcport, pi.destport);
1261                 if (conversation == NULL) {
1262                         /* It's not part of any conversation - create a new one. */
1263                         conversation = conversation_new(&pi.src, &null_address,
1264                             pi.ptype, pi.srcport, pi.destport, NULL);
1265                 }
1266
1267                 /* prepare the key data */
1268                 rpc_call_msg.xid = xid;
1269                 rpc_call_msg.conversation = conversation;
1270
1271                 /* look up the request */
1272                 if ((rpc_call = rpc_call_lookup(&rpc_call_msg)) != NULL) {
1273                         /* We've seen a request with this XID, with the same
1274                            source and destination, before - but was it
1275                            *this* request? */
1276                         if (fd->num != rpc_call->req_num) {
1277                                 /* No, so it's a duplicate request.
1278                                    Mark it as such. */
1279                                 if (check_col(fd, COL_INFO)) {
1280                                         col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
1281                                         if (rpc_tree) {
1282                                                 proto_tree_add_uint_hidden(rpc_tree,
1283                                                         hf_rpc_dup, NullTVB, 0,0, xid);
1284                                                 proto_tree_add_uint_hidden(rpc_tree,
1285                                                         hf_rpc_call_dup, NullTVB, 0,0, xid);
1286                                         }
1287                                 }
1288                         }
1289                 }
1290                 else {
1291                         /* Prepare the value data.
1292                            "req_num" and "rep_num" are frame numbers;
1293                            frame numbers are 1-origin, so we use 0
1294                            to mean "we don't yet know in which frame
1295                            the reply for this call appears". */
1296                         rpc_call_msg.req_num = fd->num;
1297                         rpc_call_msg.rep_num = 0;
1298                         rpc_call_msg.prog = prog;
1299                         rpc_call_msg.vers = vers;
1300                         rpc_call_msg.proc = proc;
1301                         rpc_call_msg.flavor = flavor;
1302                         rpc_call_msg.gss_proc = gss_proc;
1303                         rpc_call_msg.gss_svc = gss_svc;
1304                         rpc_call_msg.proc_info = value;
1305                         /* store it */
1306                         rpc_call_insert(&rpc_call_msg);
1307                 }
1308
1309                 offset += 16;
1310
1311                 offset = dissect_rpc_cred(pd, offset, fd, rpc_tree);
1312                 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1313
1314                 /* go to the next dissector */
1315
1316         } /* end of RPC call */
1317         else if (msg_type == RPC_REPLY)
1318         {
1319                 /* we know already the type from the calling routine,
1320                    and we already have "rpc_call" set above. */
1321                 prog = rpc_call->prog;
1322                 vers = rpc_call->vers;
1323                 proc = rpc_call->proc;
1324                 flavor = rpc_call->flavor;
1325                 gss_proc = rpc_call->gss_proc;
1326                 gss_svc = rpc_call->gss_svc;
1327
1328                 /* Indicate the frame to which this is a reply. */
1329                 proto_tree_add_text(rpc_tree, NullTVB, 0, 0,
1330                     "This is a reply to a request starting in frame %u",
1331                     rpc_call->req_num);
1332
1333                 if (rpc_call->proc_info != NULL) {
1334                         dissect_function = rpc_call->proc_info->dissect_reply;
1335                         if (rpc_call->proc_info->name != NULL) {
1336                                 procname = rpc_call->proc_info->name;
1337                         }
1338                         else {
1339                                 sprintf(procname_static, "proc-%u", proc);
1340                                 procname = procname_static;
1341                         }
1342                 }
1343                 else {
1344                         dissect_function = NULL;
1345                         sprintf(procname_static, "proc-%u", proc);
1346                         procname = procname_static;
1347                 }
1348
1349                 rpc_prog_key.prog = prog;
1350                 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
1351                         proto = 0;
1352                         ett = 0;
1353                         progname = "Unknown";
1354                 }
1355                 else {
1356                         proto = rpc_prog->proto;
1357                         ett = rpc_prog->ett;
1358                         progname = rpc_prog->progname;
1359
1360                         if (check_col(fd, COL_PROTOCOL)) {
1361                                 /* Set the protocol name to the underlying
1362                                    program name. */
1363                                 col_add_fstr(fd, COL_PROTOCOL, "%s",
1364                                     progname);
1365                         }
1366                 }
1367
1368                 if (check_col(fd, COL_INFO)) {
1369                         col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
1370                                 vers,
1371                                 procname,
1372                                 msg_type_name,
1373                                 xid);
1374                 }
1375
1376                 if (rpc_tree) {
1377                         proto_tree_add_uint_format(rpc_tree,
1378                                 hf_rpc_program, NullTVB, 0, 0, prog,
1379                                 "Program: %s (%u)", progname, prog);
1380                         proto_tree_add_uint(rpc_tree,
1381                                 hf_rpc_programversion, NullTVB, 0, 0, vers);
1382                         proto_tree_add_uint_format(rpc_tree,
1383                                 hf_rpc_procedure, NullTVB, 0, 0, proc,
1384                                 "Procedure: %s (%u)", procname, proc);
1385                 }
1386
1387                 if (rpc_call->rep_num == 0) {
1388                         /* We have not yet seen a reply to that call, so
1389                            this must be the first reply; remember its
1390                            frame number. */
1391                         rpc_call->rep_num = fd->num;
1392                 } else {
1393                         /* We have seen a reply to this call - but was it
1394                            *this* reply? */
1395                         if (rpc_call->rep_num != fd->num) {
1396                                 /* No, so it's a duplicate reply.
1397                                    Mark it as such. */
1398                                 if (check_col(fd, COL_INFO)) {
1399                                         col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
1400                                         if (rpc_tree) {
1401                                                 proto_tree_add_uint_hidden(rpc_tree,
1402                                                         hf_rpc_dup, NullTVB, 0,0, xid);
1403                                                 proto_tree_add_uint_hidden(rpc_tree,
1404                                                         hf_rpc_reply_dup, NullTVB, 0,0, xid);
1405                                         }
1406                                 }
1407                         }
1408                 }
1409
1410                 if (!BYTES_ARE_IN_FRAME(offset,4))
1411                         return TRUE;
1412                 reply_state = EXTRACT_UINT(pd,offset+0);
1413                 if (rpc_tree) {
1414                         proto_tree_add_uint(rpc_tree, hf_rpc_state_reply, NullTVB,
1415                                 offset+0, 4, reply_state);
1416                 }
1417                 offset += 4;
1418
1419                 if (reply_state == MSG_ACCEPTED) {
1420                         offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1421                         if (!BYTES_ARE_IN_FRAME(offset,4))
1422                                 return TRUE;
1423                         accept_state = EXTRACT_UINT(pd,offset+0);
1424                         if (rpc_tree) {
1425                                 proto_tree_add_uint(rpc_tree, hf_rpc_state_accept, NullTVB,
1426                                         offset+0, 4, accept_state);
1427                         }
1428                         offset += 4;
1429                         switch (accept_state) {
1430                                 case SUCCESS:
1431                                         /* go to the next dissector */
1432                                 break;
1433                                 case PROG_MISMATCH:
1434                                         if (!BYTES_ARE_IN_FRAME(offset,8))
1435                                                 return TRUE;
1436                                         vers_low = EXTRACT_UINT(pd,offset+0);
1437                                         vers_high = EXTRACT_UINT(pd,offset+4);
1438                                         if (rpc_tree) {
1439                                                 proto_tree_add_uint(rpc_tree,
1440                                                         hf_rpc_programversion_min,
1441                                                         NullTVB, offset+0, 4, vers_low);
1442                                                 proto_tree_add_uint(rpc_tree,
1443                                                         hf_rpc_programversion_max,
1444                                                         NullTVB, offset+4, 4, vers_high);
1445                                         }
1446                                         offset += 8;
1447                                 break;
1448                                 default:
1449                                         /* void */
1450                                 break;
1451                         }
1452                 } else if (reply_state == MSG_DENIED) {
1453                         if (!BYTES_ARE_IN_FRAME(offset,4))
1454                                 return TRUE;
1455                         reject_state = EXTRACT_UINT(pd,offset+0);
1456                         if (rpc_tree) {
1457                                 proto_tree_add_uint(rpc_tree,
1458                                         hf_rpc_state_reject, NullTVB, offset+0, 4,
1459                                         reject_state);
1460                         }
1461                         offset += 4;
1462
1463                         if (reject_state==RPC_MISMATCH) {
1464                                 if (!BYTES_ARE_IN_FRAME(offset,8))
1465                                         return TRUE;
1466                                 vers_low = EXTRACT_UINT(pd,offset+0);
1467                                 vers_high = EXTRACT_UINT(pd,offset+4);
1468                                 if (rpc_tree) {
1469                                         proto_tree_add_uint(rpc_tree,
1470                                                 hf_rpc_version_min,
1471                                                 NullTVB, offset+0, 4, vers_low);
1472                                         proto_tree_add_uint(rpc_tree,
1473                                                 hf_rpc_version_max,
1474                                                 NullTVB, offset+4, 4, vers_high);
1475                                 }
1476                                 offset += 8;
1477                         } else if (reject_state==AUTH_ERROR) {
1478                                 if (!BYTES_ARE_IN_FRAME(offset,4))
1479                                         return TRUE;
1480                                 auth_state = EXTRACT_UINT(pd,offset+0);
1481                                 if (rpc_tree) {
1482                                         proto_tree_add_uint(rpc_tree,
1483                                                 hf_rpc_state_auth, NullTVB, offset+0, 4,
1484                                                 auth_state);
1485                                 }
1486                                 offset += 4;
1487                         }
1488                 } 
1489         } /* end of RPC reply */
1490
1491         /* now we know, that RPC was shorter */
1492         if (rpc_item) {
1493                 proto_item_set_len(rpc_item, offset - offset_old);
1494         }
1495
1496         /* create here the program specific sub-tree */
1497         if (tree) {
1498                 pitem = proto_tree_add_item(tree, proto, NullTVB, offset, END_OF_FRAME, FALSE);
1499                 if (pitem) {
1500                         ptree = proto_item_add_subtree(pitem, ett);
1501                 }
1502
1503                 if (ptree) {
1504                         proto_tree_add_uint(ptree,
1505                                 hf_rpc_programversion, NullTVB, 0, 0, vers);
1506                         proto_tree_add_uint_format(ptree,
1507                                 hf_rpc_procedure, NullTVB, 0, 0, proc,
1508                                 "Procedure: %s (%u)", procname, proc);
1509                 }
1510         }
1511
1512         /* RPCSEC_GSS processing. */
1513         if (flavor == RPCSEC_GSS) {
1514                 switch (gss_proc) {
1515                 case RPCSEC_GSS_INIT:
1516                 case RPCSEC_GSS_CONTINUE_INIT:
1517                         if (msg_type == RPC_CALL) {
1518                                 offset = dissect_rpc_authgss_initarg(pd, offset, fd, ptree);
1519                         }
1520                         else {
1521                                 offset = dissect_rpc_authgss_initres(pd, offset, fd, ptree);
1522                         }
1523                         break;
1524                 case RPCSEC_GSS_DATA:
1525                         if (gss_svc == RPCSEC_GSS_SVC_NONE) {
1526                                 if (dissect_function != NULL && 
1527                                         proto_is_protocol_enabled(proto))
1528                                         offset = dissect_function(pd, offset, fd, ptree);
1529                         }
1530                         else if (gss_svc == RPCSEC_GSS_SVC_INTEGRITY) {
1531                                 offset = dissect_rpc_authgss_integ_data(pd, offset, fd, ptree, 
1532                                 (proto_is_protocol_enabled(proto) ? 
1533                                 dissect_function : NULL));
1534                         }
1535                         else if (gss_svc == RPCSEC_GSS_SVC_PRIVACY) {
1536                                 offset = dissect_rpc_authgss_priv_data(pd, offset, fd, ptree);
1537                         }
1538                         break;
1539                 default:
1540                         dissect_function = NULL;
1541                         break;
1542                 }
1543         }
1544         else if (dissect_function != NULL &&
1545                 proto_is_protocol_enabled(proto)) {
1546                 offset = dissect_function(pd, offset, fd, ptree);
1547         }
1548
1549         /* dissect any remaining bytes (incomplete dissection) as pure data in
1550            the ptree */
1551         old_dissect_data(pd, offset, fd, ptree);
1552
1553         return TRUE;
1554 }
1555
1556
1557 /* Discard any state we've saved. */
1558 static void
1559 rpc_init_protocol(void)
1560 {
1561         memset(rpc_call_table, '\0', sizeof rpc_call_table);
1562         rpc_call_index = 0;
1563         rpc_call_firstfree = 0;
1564 }
1565
1566
1567 /* will be called once from register.c at startup time */
1568 void
1569 proto_register_rpc(void)
1570 {
1571         static hf_register_info hf[] = {
1572                 { &hf_rpc_lastfrag, {
1573                         "Last Fragment", "rpc.lastfrag", FT_BOOLEAN, BASE_NONE,
1574                         &yesno, 0, "Last Fragment" }},
1575                 { &hf_rpc_fraglen, {
1576                         "Fragment Length", "rpc.fraglen", FT_UINT32, BASE_DEC,
1577                         NULL, 0, "Fragment Length" }},
1578                 { &hf_rpc_xid, {
1579                         "XID", "rpc.xid", FT_UINT32, BASE_HEX,
1580                         NULL, 0, "XID" }},
1581                 { &hf_rpc_msgtype, {
1582                         "Message Type", "rpc.msgtyp", FT_UINT32, BASE_DEC,
1583                         VALS(rpc_msg_type), 0, "Message Type" }},
1584                 { &hf_rpc_state_reply, {
1585                         "Reply State", "rpc.replystat", FT_UINT32, BASE_DEC,
1586                         VALS(rpc_reply_state), 0, "Reply State" }},
1587                 { &hf_rpc_state_accept, {
1588                         "Accept State", "rpc.state_accept", FT_UINT32, BASE_DEC,
1589                         VALS(rpc_accept_state), 0, "Accept State" }},
1590                 { &hf_rpc_state_reject, {
1591                         "Reject State", "rpc.state_reject", FT_UINT32, BASE_DEC,
1592                         VALS(rpc_reject_state), 0, "Reject State" }},
1593                 { &hf_rpc_state_auth, {
1594                         "Auth State", "rpc.state_auth", FT_UINT32, BASE_DEC,
1595                         VALS(rpc_auth_state), 0, "Auth State" }},
1596                 { &hf_rpc_version, {
1597                         "RPC Version", "rpc.version", FT_UINT32, BASE_DEC,
1598                         NULL, 0, "RPC Version" }},
1599                 { &hf_rpc_version_min, {
1600                         "RPC Version (Minimum)", "rpc.version.min", FT_UINT32, 
1601                         BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1602                 { &hf_rpc_version_max, {
1603                         "RPC Version (Maximum)", "rpc.version.max", FT_UINT32, 
1604                         BASE_DEC, NULL, 0, "RPC Version (Maximum)" }},
1605                 { &hf_rpc_program, {
1606                         "Program", "rpc.program", FT_UINT32, BASE_DEC,
1607                         NULL, 0, "Program" }},
1608                 { &hf_rpc_programversion, {
1609                         "Program Version", "rpc.programversion", FT_UINT32, 
1610                         BASE_DEC, NULL, 0, "Program Version" }},
1611                 { &hf_rpc_programversion_min, {
1612                         "Program Version (Minimum)", "rpc.programversion.min", FT_UINT32, 
1613                         BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1614                 { &hf_rpc_programversion_max, {
1615                         "Program Version (Maximum)", "rpc.programversion.max", FT_UINT32, 
1616                         BASE_DEC, NULL, 0, "Program Version (Maximum)" }},
1617                 { &hf_rpc_procedure, {
1618                         "Procedure", "rpc.procedure", FT_UINT32, BASE_DEC,
1619                         NULL, 0, "Procedure" }},
1620                 { &hf_rpc_auth_flavor, {
1621                         "Flavor", "rpc.auth.flavor", FT_UINT32, BASE_DEC,
1622                         VALS(rpc_auth_flavor), 0, "Flavor" }},
1623                 { &hf_rpc_auth_length, {
1624                         "Length", "rpc.auth.length", FT_UINT32, BASE_DEC,
1625                         NULL, 0, "Length" }},
1626                 { &hf_rpc_auth_stamp, {
1627                         "Stamp", "rpc.auth.stamp", FT_UINT32, BASE_HEX,
1628                         NULL, 0, "Stamp" }},
1629                 { &hf_rpc_auth_uid, {
1630                         "UID", "rpc.auth.uid", FT_UINT32, BASE_DEC,
1631                         NULL, 0, "UID" }},
1632                 { &hf_rpc_auth_gid, {
1633                         "GID", "rpc.auth.gid", FT_UINT32, BASE_DEC,
1634                         NULL, 0, "GID" }},
1635                 { &hf_rpc_authgss_v, {
1636                         "GSS Version", "rpc.authgss.version", FT_UINT32,
1637                         BASE_DEC, NULL, 0, "GSS Version" }},
1638                 { &hf_rpc_authgss_proc, {
1639                         "GSS Procedure", "rpc.authgss.procedure", FT_UINT32,
1640                         BASE_DEC, VALS(rpc_authgss_proc), 0, "GSS Procedure" }},
1641                 { &hf_rpc_authgss_seq, {
1642                         "GSS Sequence Number", "rpc.authgss.seqnum", FT_UINT32,
1643                         BASE_DEC, NULL, 0, "GSS Sequence Number" }},
1644                 { &hf_rpc_authgss_svc, {
1645                         "GSS Service", "rpc.authgss.service", FT_UINT32,
1646                         BASE_DEC, VALS(rpc_authgss_svc), 0, "GSS Service" }},
1647                 { &hf_rpc_authgss_ctx, {
1648                         "GSS Context", "rpc.authgss.context", FT_BYTES,
1649                         BASE_HEX, NULL, 0, "GSS Context" }},
1650                 { &hf_rpc_authgss_major, {
1651                         "GSS Major Status", "rpc.authgss.major", FT_UINT32,
1652                         BASE_DEC, NULL, 0, "GSS Major Status" }},
1653                 { &hf_rpc_authgss_minor, {
1654                         "GSS Minor Status", "rpc.authgss.minor", FT_UINT32,
1655                         BASE_DEC, NULL, 0, "GSS Minor Status" }},
1656                 { &hf_rpc_authgss_window, {
1657                         "GSS Sequence Window", "rpc.authgss.window", FT_UINT32,
1658                         BASE_DEC, NULL, 0, "GSS Sequence Window" }},
1659                 { &hf_rpc_authgss_token, {
1660                         "GSS Token", "rpc.authgss.token", FT_BYTES,
1661                         BASE_HEX, NULL, 0, "GSS Token" }},
1662                 { &hf_rpc_authgss_data_length, {
1663                         "Length", "rpc.authgss.data.length", FT_UINT32,
1664                         BASE_DEC, NULL, 0, "Length" }},
1665                 { &hf_rpc_authgss_data, {
1666                         "GSS Data", "rpc.authgss.data", FT_BYTES,
1667                         BASE_HEX, NULL, 0, "GSS Data" }},
1668                 { &hf_rpc_authgss_checksum, {
1669                         "GSS Checksum", "rpc.authgss.checksum", FT_BYTES,
1670                         BASE_HEX, NULL, 0, "GSS Checksum" }},
1671                 { &hf_rpc_auth_machinename, {
1672                         "Machine Name", "rpc.auth.machinename", FT_STRING, 
1673                         BASE_DEC, NULL, 0, "Machine Name" }},
1674                 { &hf_rpc_dup, {
1675                         "Duplicate Transaction", "rpc.dup", FT_UINT32, BASE_DEC,
1676                         NULL, 0, "Duplicate Transaction" }},
1677                 { &hf_rpc_call_dup, {
1678                         "Duplicate Call", "rpc.call.dup", FT_UINT32, BASE_DEC,
1679                         NULL, 0, "Duplicate Call" }},
1680                 { &hf_rpc_reply_dup, {
1681                         "Duplicate Reply", "rpc.reply.dup", FT_UINT32, BASE_DEC,
1682                         NULL, 0, "Duplicate Reply" }},
1683                 { &hf_rpc_value_follows, {
1684                         "Value Follows", "rpc.value_follows", FT_BOOLEAN, BASE_NONE,
1685                         &yesno, 0, "Value Follows" }}
1686         };
1687         static gint *ett[] = {
1688                 &ett_rpc,
1689                 &ett_rpc_string,
1690                 &ett_rpc_cred,
1691                 &ett_rpc_verf,
1692                 &ett_rpc_gids,
1693         };
1694
1695         proto_rpc = proto_register_protocol("Remote Procedure Call", "rpc");
1696         proto_register_field_array(proto_rpc, hf, array_length(hf));
1697         proto_register_subtree_array(ett, array_length(ett));
1698         register_init_routine(&rpc_init_protocol);
1699
1700         /*
1701          * Init the hash tables.  Dissectors for RPC protocols must
1702          * have a "handoff registration" routine that registers the
1703          * protocol with RPC; they must not do it in their protocol
1704          * registration routine, as their protocol registration
1705          * routine might be called before this routine is called and
1706          * thus might be called before the hash tables are initialized,
1707          * but it's guaranteed that all protocol registration routines
1708          * will be called before any handoff registration routines
1709          * are called.
1710          */
1711         rpc_progs = g_hash_table_new(rpc_prog_hash, rpc_prog_equal);
1712         rpc_procs = g_hash_table_new(rpc_proc_hash, rpc_proc_equal);
1713 }
1714
1715
1716 void
1717 proto_reg_handoff_rpc(void)
1718 {
1719         old_heur_dissector_add("tcp", dissect_rpc);
1720         old_heur_dissector_add("udp", dissect_rpc);
1721 }
1722
1723