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