Do not use "match_strval()" unless you're prepared to check whether it
[obnox/wireshark/wip.git] / packet-giop.c
1 /* packet-giop.c
2  * Routines for CORBA GIOP/IIOP packet disassembly
3  *
4  * Laurent Deniel <deniel@worldnet.fr>
5  * Craig Rodrigues <rodrigc@mediaone.net>
6  *
7  * $Id: packet-giop.c,v 1.29 2001/01/16 23:35:58 guy Exp $
8  *
9  * Ethereal - Network traffic analyzer
10  * By Gerald Combs <gerald@zing.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * 
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  * 
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  *
28  *
29  */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
37 #endif
38
39 #include <string.h>
40 #include <ctype.h>
41 #include <glib.h>
42 #include "packet.h"
43
44 static int proto_giop = -1;
45 static int hf_giop_message_type = -1;
46 static int hf_giop_message_size = -1;
47
48 static gint ett_giop = -1;
49 static gint ett_giop_reply = -1;
50 static gint ett_giop_request = -1;
51 static gint ett_giop_cancel_request = -1;
52 static gint ett_giop_locate_request = -1;
53 static gint ett_giop_locate_reply = -1;
54 static gint ett_giop_fragment = -1;
55
56 static const value_string sync_scope[] = {
57         { 0x0, "SYNC_NONE" },
58         { 0x1, "SYNC_WITH_TRANSPORT"},
59         { 0x2, "SYNC_WITH_SERVER"},
60         { 0x3, "SYNC_WITH_TARGET"},
61         { 0, NULL}
62 };
63
64 static const value_string giop_message_types[] = {
65         { 0x0, "Request" },
66         { 0x1, "Reply"},
67         { 0x2, "CancelRequest"},
68         { 0x3, "LocateRequest"},
69         { 0x4, "LocateReply"},
70         { 0x5, "CloseConnection"},
71         { 0x6, "MessageError"},
72         { 0x7, "Fragment"},
73         { 0, NULL}
74 };
75
76 static const value_string giop_locate_status_types[] = {
77         { 0x0, "Unknown Object" },
78         { 0x1, "Object Here"},
79         { 0x2, "Object Forward"},
80         { 0x3, "Object Forward Perm"},
81         { 0x4, "Loc System Exception"},
82         { 0x5, "Loc Needs Addressing Mode"},
83         { 0, NULL }     
84 };
85
86
87 /*
88  * GIOP / IIOP types definition - OMG CORBA 2.x / GIOP 1.[012]
89  * See CORBA 2.4 specification: http://cgi.omg.org/cgi-bin/doc?formal/00-10-1
90  *
91  * Notes on mapping:
92  *
93  * <sequence> : unsigned int (# elts) + elements
94  * <string>   : unsigned int (string length) + length characters (with '\0')
95  * <enum>     : unsigned int (from 0 to n)
96  */
97
98 #define GIOP_MAGIC       "GIOP"
99 static const guint GIOP_MAJOR =  1;
100 static const guint GIOP_MINOR =  2;
101
102 static const guint GIOP_HEADER_SIZE = 12;
103
104 static const int KeyAddr       = 0;
105 static const int ProfileAddr   = 1;
106 static const int ReferenceAddr = 2;
107
108 typedef struct OctetSequence
109 {
110   guint32 sequence_length;
111   guint8 sequence_data[1];      /* of length bytes */
112 }
113 OctetSequence;
114
115 typedef OctetSequence Principal;
116 typedef OctetSequence String;
117
118 /* 
119  * Some structures that contain sequences can not be directly used 
120  * (alignment problem on 64 bit architectures)
121  */
122
123 typedef struct ServiceContext
124 {
125   guint32 context_id;
126   OctetSequence context_data;
127 }
128 ServiceContext;
129
130 typedef struct ServiceContextList
131 {
132   guint32 nr_context;
133   ServiceContext service_context[1];    /* nr_context elements */
134 }
135 ServiceContextList;
136
137 typedef enum MsgType
138 {
139   Request,
140   Reply,
141   CancelRequest,
142   LocateRequest,
143   LocateReply,
144   CloseConnection,
145   MessageError,
146   Fragment                      /* GIOP 1.1 only */
147 }
148 MsgType;
149
150 typedef struct Version
151 {
152   guint8 major;
153   guint8 minor;
154 }
155 Version;
156
157 typedef struct MessageHeader
158 {
159   guint8 magic[4];
160   Version GIOP_version;
161   guint8 flags;                 /* byte_order in 1.0 */
162   guint8 message_type;
163   guint32 message_size;
164 }
165 MessageHeader;
166
167 typedef struct RequestHeader_1_0
168 {
169   /* ServiceContextList service_context; */
170   guint32 request_id;
171   guint8 response_expected;
172   OctetSequence object_key;
173   /* String     operation;              */
174   /* Principal  requesting_principal;   */
175 }
176 RequestHeader_1_0;
177
178 typedef struct RequestHeader_1_1
179 {
180   /* ServiceContextList service_context; */
181   guint32 request_id;
182   guint8 response_expected;
183   guint8 reserved[3];
184   OctetSequence object_key;
185   /* String     operation;              */
186   /* Principal  requesting_principal;   */
187 }
188 RequestHeader_1_1;
189
190 typedef enum ReplyStatusType
191 {
192   NO_EXCEPTION,
193   USER_EXCEPTION,
194   SYSTEM_EXCEPTION,
195   LOCATION_FORWARD,
196   LOCATION_FORWARD_PERM,        /* new for GIOP 1.2 */
197   NEEDS_ADDRESSING_MODE         /* new for GIOP 1.2 */
198 }
199 ReplyStatusType;
200
201 const static value_string reply_status_types[] = { 
202    { NO_EXCEPTION, "No Exception" } ,
203    { USER_EXCEPTION, "User Exception" } ,
204    { SYSTEM_EXCEPTION, "System Exception" } ,
205    { LOCATION_FORWARD, "Location Forward" } ,
206    { LOCATION_FORWARD_PERM, "Location Forward Perm" } ,
207    { NEEDS_ADDRESSING_MODE, "Needs Addressing Mode"} ,
208    { 0, NULL }
209 };
210
211 typedef struct ReplyHeader
212 {
213   /* ServiceContext service_context;    */
214   guint32 request_id;
215   guint32 reply_status;
216 }
217 ReplyHeader;
218
219 typedef struct SystemExceptionReplyBody
220 {
221   String exception_id;
222   u_int minor_code_value;
223   u_int completion_status;
224 }
225 SystemExceptionReplyBody;
226
227 typedef struct CancelRequestHeader
228 {
229   guint32 request_id;
230 }
231 CancelRequestHeader;
232
233 typedef struct LocateRequestHeader
234 {
235   guint32 request_id;
236   OctetSequence object_key;
237 }
238 LocateRequestHeader;
239
240 typedef enum LocateStatusType
241 {
242   UNKNOWN_OBJECT,
243   OBJECT_HERE,
244   OBJECT_FORWARD,
245   OBJECT_FORWARD_PERM,      // new value for GIOP 1.2
246   LOC_SYSTEM_EXCEPTION,     // new value for GIOP 1.2
247   LOC_NEEDS_ADDRESSING_MODE // new value for GIOP 1.2
248 }
249 LocateStatusType;
250
251 typedef struct LocateReplyHeader
252 {
253   guint32 request_id;
254   guint32 locate_status;
255 }
256 LocateReplyHeader;
257
258 /* Take in a string and replace non-printable characters with periods */
259 static void
260 printable_string (gchar *in, guint32 len)
261 {
262   int i = 0;
263
264   for(i=0; i < len; i++)
265   {
266          if( !isprint( (unsigned char)in[i] ) ) 
267                  in[i] = '.';
268   }
269 }
270
271 /* Determine the byte order from the GIOP MessageHeader */
272 static gboolean 
273 is_big_endian (MessageHeader * header)
274 {
275   gboolean big_endian = FALSE;
276
277   switch (header->GIOP_version.minor)
278     {
279     case 2:
280     case 1:
281       if (header->flags & 0x01)
282         big_endian = FALSE;
283       else
284         big_endian = TRUE;
285       break;
286     case 0:
287       if (header->flags)
288         big_endian = FALSE;
289       else
290         big_endian = TRUE;
291       break;
292     default:
293       break;
294     }
295   return big_endian;
296 }
297
298 /* Copy a 4 octet sequence from the tvbuff 
299  * which represents an unsigned long value, and convert
300  * it to an unsigned long vaule, taking into account byte order.
301  * offset is first incremented so that it falls on a proper alignment
302  * boundary for unsigned long values.
303  * offset is then incremented by 4, to indicate the 4 octets which
304  * have been processed.
305  */
306 static guint32
307 get_CDR_ulong(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian)
308 {
309   guint32 val;
310
311   /* unsigned long values must be aligned on a 4 byte boundary */
312   while( ( (*offset + GIOP_HEADER_SIZE) % 4) != 0)
313           ++(*offset);
314
315   val = (stream_is_big_endian) ? tvb_get_ntohl (tvb, *offset) :
316                                  tvb_get_letohl (tvb, *offset);
317
318   *offset += 4; 
319   return val; 
320 }
321
322 /* Copy a 2 octet sequence from the tvbuff 
323  * which represents an unsigned short value, and convert
324  * it to an unsigned short value, taking into account byte order.
325  * offset is first incremented so that it falls on a proper alignment
326  * boundary for unsigned short values.
327  * offset is then incremented by 2, to indicate the 2 octets which
328  * have been processed.
329  */
330 static guint16
331 get_CDR_ushort(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian)
332 {
333   guint16 val;
334
335   /* unsigned short values must be aligned on a 2 byte boundary */
336   while( ( (*offset + GIOP_HEADER_SIZE) % 2) != 0)
337           ++(*offset);
338
339   val = (stream_is_big_endian) ? tvb_get_ntohs (tvb, *offset) :
340                                  tvb_get_letohs (tvb, *offset);
341
342   *offset += 2; 
343   return val; 
344 }
345
346
347 /* Copy a 2 octet sequence from the tvbuff 
348  * which represents a signed short value, and convert
349  * it to a signed short value, taking into account byte order.
350  * offset is first incremented so that it falls on a proper alignment
351  * boundary for unsigned short values.
352  * offset is then incremented by 2, to indicate the 2 octets which
353  * have been processed.
354  */
355
356 gint16
357 get_CDR_short(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian)
358 {
359   gint16 val;
360
361   /* short values must be aligned on a 2 byte boundary */
362   while( ( (*offset + GIOP_HEADER_SIZE) % 2) != 0)
363           ++(*offset);
364
365   val = (stream_is_big_endian) ? tvb_get_ntohs (tvb, *offset) :
366                                  tvb_get_letohs (tvb, *offset);
367
368   *offset += 2; 
369   return val; 
370 }
371
372
373
374 /* Copy a sequence of octets from the tvbuff.
375  * Caller of this function must remember to free the 
376  * array pointed to by seq.
377  * This function also increments offset by len. 
378  */
379 static void
380 get_CDR_octet_seq(tvbuff_t *tvb, gchar **seq, int *offset, int len)
381 {
382      *seq = g_new0(gchar, len + 1);
383      tvb_memcpy( tvb, *seq, *offset, len);
384      *offset += len;
385 }
386
387 /**
388  *  Dissects a TargetAddress which is defined in (CORBA 2.4, section 15.4.2)
389  *  // GIOP 1.2
390  *  typedef short AddressingDisposition;
391  *  const short KeyAddr = 0;
392  *  const short ProfileAddr = 1;
393  *  const short ReferenceAddr = 2;
394  *  struct IORAddressingInfo {
395  *    unsigned long selected_profile_index;
396  *    IOP::IOR ior;
397  *  };
398  *
399  *  union TargetAddress switch (AddressingDisposition) {
400  *      case KeyAddr: sequence <octet> object_key;
401  *      case ProfileAddr: IOP::TaggedProfile profile;
402  *      case ReferenceAddr: IORAddressingInfo ior;
403  *  };
404  */
405 static void
406 dissect_target_address(tvbuff_t * tvb, int *offset, proto_tree * sub_tree, 
407                        MessageHeader * header, gboolean stream_is_big_endian)
408 {
409    guint16 discriminant;
410    gchar *object_key = NULL;
411    guint32 len = 0;
412
413    discriminant = get_CDR_ushort(tvb, offset, stream_is_big_endian);
414    if(sub_tree)
415    {
416      proto_tree_add_text (sub_tree, tvb, *offset -2, 2,
417                  "TargetAddress Discriminant: %u", discriminant);
418    }
419   
420    switch (discriminant)
421    {
422            case 0:  // KeyAddr
423                    len = get_CDR_ulong(tvb, offset, stream_is_big_endian);
424                    get_CDR_octet_seq(tvb, &object_key, offset, len);
425                    printable_string( object_key, len );
426
427                    if(sub_tree)
428                    {
429                       proto_tree_add_text (sub_tree, tvb, *offset -len -4, 4,
430                                            "KeyAddr (object key length): %u", len);
431                       proto_tree_add_text (sub_tree, tvb, *offset -len, len,
432                                            "KeyAddr (object key): %s", object_key);
433                    }
434                    break;
435            case 1:
436                    if(sub_tree)
437                    {
438                       proto_tree_add_text (sub_tree, tvb, *offset, tvb_length(tvb) - *offset,
439                                            "ProfileAddr (not implemented) %s", object_key);
440                    }
441                    break;
442            case 2:
443                    if(sub_tree)
444                    {
445                       proto_tree_add_text (sub_tree, tvb, *offset, tvb_length(tvb) - *offset,
446                                            "ReferenceAddr (not implemented) %s", object_key);
447                    }
448                    break;
449            default:
450                    break;
451    }
452    g_free( object_key );
453 }
454
455 static void
456 dissect_reply_body (tvbuff_t *tvb, u_int offset, packet_info *pinfo,
457                     proto_tree *tree, gboolean stream_is_big_endian,
458                     guint32 reply_status)
459 {
460   u_int sequence_length;
461   u_int minor_code_value;
462   u_int completion_status;
463
464   switch (reply_status)
465     {
466     case SYSTEM_EXCEPTION:
467       if (tree)
468         {
469           sequence_length = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
470
471           proto_tree_add_text(tree, tvb, offset-4, 4,
472                            "Exception length: %u", sequence_length);
473
474           if (sequence_length != 0)
475             {
476               proto_tree_add_text(tree, tvb, offset, sequence_length,
477                            "Exception id: %s",
478                            tvb_format_text(tvb, offset, sequence_length - 1));
479               offset += sequence_length;
480             }
481
482           minor_code_value = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
483           completion_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
484         
485           proto_tree_add_text(tree, tvb, offset-8, 4,
486                            "Minor code value: %u", minor_code_value);
487           proto_tree_add_text(tree, tvb, offset-4, 4,
488                            "Completion Status: %u", completion_status);
489         }
490       break;
491
492     case USER_EXCEPTION:
493       if (tree)
494         {
495           sequence_length = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
496
497           proto_tree_add_text(tree, tvb, offset-4, 4,
498                            "Exception length: %u", sequence_length);
499
500           if (sequence_length != 0)
501             {
502               proto_tree_add_text(tree, tvb, offset, sequence_length,
503                            "Exception id: %s",
504                            tvb_format_text(tvb, offset, sequence_length));
505
506               offset += sequence_length;
507             }
508
509           sequence_length = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
510           proto_tree_add_text(tree, tvb, offset-4, 4,
511                            "Exception member length: %u", sequence_length);
512
513           if (sequence_length != 0)
514             {
515               proto_tree_add_text(tree, tvb, offset, sequence_length,
516                            "Exception member: %s",
517                            tvb_format_text(tvb, offset, sequence_length - 1));
518             }
519
520         }
521       break;
522
523     default:
524         if (tree)
525           {
526             proto_tree_add_text(tree, tvb, offset,
527                            tvb_length_remaining(tvb, offset),
528                            "Reply body: <not shown>");
529           }
530     }
531 }
532
533 /* The format of the Reply Header for GIOP 1.0 and 1.1
534  * is documented in Section 15.4.3.1 * of the CORBA 2.4 standard.
535
536     struct ReplyHeader_1_0 {
537           IOP::ServiceContextList service_context;
538           unsigned long request_id;
539           ReplyStatusType_1_0 reply_status;
540     };
541  */
542 static void
543 dissect_giop_reply (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
544                     proto_tree * clnp_tree, MessageHeader * header,
545                     gboolean stream_is_big_endian)
546 {
547   guint32 offset = 0;
548   guint32 nr_seq = 0;
549   guint32 context_id;
550   guint32 sequence_length;
551   guint32 request_id;
552   guint32 reply_status;
553   gboolean big_endian;
554   proto_tree *reply_tree = NULL;
555   proto_item *tf;
556
557   int i;
558
559   big_endian = is_big_endian (header);
560
561   /* From Section 15.3.2.5 of the CORBA 2.4 standard, a sequence
562    * is an unsigned long value (4 octets) indicating the number of 
563    * items in the sequence, followed by the items in the sequence 
564    */
565
566   /* The format of the IOP::ServiceContextList struct is defined in
567    * section 13.7 of the CORBA 2.4 standard  as:
568    module IOP { // IDL
569    typedef unsigned long ServiceId;
570
571    struct ServiceContext {
572    ServiceId context_id;
573    sequence <octet> context_data;
574    };
575    typedef sequence <ServiceContext>ServiceContextList;
576    };
577    */
578   if (tree)
579     {
580       tf = proto_tree_add_text (tree, tvb, offset,
581                                 tvb_length (tvb),
582                                 "General Inter-ORB Protocol Reply");
583       if (reply_tree == NULL)
584         {
585           reply_tree = proto_item_add_subtree (tf, ett_giop_reply);
586
587         }
588     }
589
590   nr_seq = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
591
592   for (i = 1; i <= nr_seq; i++)
593     {
594
595       if (big_endian)
596         {
597           context_id = tvb_get_ntohl (tvb, offset);
598           sequence_length = tvb_get_ntohl (tvb, offset + 4);
599         }
600       else
601         {
602           context_id = tvb_get_letohl (tvb, offset);
603           sequence_length = tvb_get_letohl (tvb, offset + 4);
604         }
605
606       context_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
607
608       if (tree)
609         {
610           proto_tree_add_text (reply_tree, tvb, offset -4, 4,
611                                "Context id: %u", context_id);
612         }
613
614       sequence_length = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
615       if(tree)
616       {      
617           proto_tree_add_text (reply_tree, tvb, offset -4,
618                                4, "Sequence length: %u", sequence_length);
619       }
620
621       if(tree)
622       {
623           if (sequence_length > 0)
624             {
625               proto_tree_add_text (reply_tree, tvb, offset,
626                                    sequence_length,
627                                    "Sequence data: <not shown>");
628             }
629         }
630
631       offset += sequence_length;        
632
633     }                           /* for */
634
635   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
636   if (check_col(pinfo->fd, COL_INFO))
637     {
638       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
639     }
640   if (tree)
641     {
642       proto_tree_add_text (reply_tree, tvb, offset-4, 4,
643                            "Request id: %u", request_id);
644     }
645
646   reply_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
647   if (check_col(pinfo->fd, COL_INFO))
648     {
649       col_append_fstr(pinfo->fd, COL_INFO, ": %s",
650         val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
651     }
652   if (tree)
653     {
654       proto_tree_add_text (reply_tree, tvb, offset-4, 4,
655         "Reply status: %s",
656         val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
657
658     }
659
660   dissect_reply_body(tvb, offset, pinfo, reply_tree, stream_is_big_endian,
661     reply_status);
662 }
663
664 /** The format of the GIOP 1.2 Reply header is very similar to the 1.0
665  *  and 1.1 header, only the fields have been rearranged.  From Section
666  *  15.4.3.1 of the CORBA 2.4 specification:
667  *
668  *   struct ReplyHeader_1_2 {
669           unsigned long request_id;
670           ReplyStatusType_1_2 reply_status;
671           IOP:ServiceContextList service_context; // 1.2 change
672      };
673  */
674 static void
675 dissect_giop_reply_1_2 (tvbuff_t * tvb, packet_info * pinfo,
676                         proto_tree * tree, proto_tree * clnp_tree,
677                         MessageHeader * header,
678                         gboolean stream_is_big_endian)
679 {
680   u_int offset = 0;
681   guint32 nr_seq = 0;
682   guint32 context_id;
683   guint32 sequence_length;
684   guint32 request_id;
685   guint32 reply_status;
686   proto_tree *reply_tree = NULL;
687   proto_item *tf;
688   int i;
689
690   if (tree)
691     {
692       tf = proto_tree_add_text (tree, tvb, offset,
693                                 tvb_length (tvb),
694                                 "General Inter-ORB Protocol Reply");
695       if (reply_tree == NULL)
696         {
697           reply_tree = proto_item_add_subtree (tf, ett_giop_reply);
698
699         }
700     }
701
702   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
703   if (check_col(pinfo->fd, COL_INFO))
704     {
705       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
706     }
707   if (tree)
708     {
709       proto_tree_add_text (reply_tree, tvb, offset-4, 4,
710                            "Request id: %u", request_id);
711     }
712
713   reply_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
714   if (check_col(pinfo->fd, COL_INFO))
715     {
716       col_append_fstr(pinfo->fd, COL_INFO, ": %s",
717         val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
718     }
719   if (tree)
720     {
721       proto_tree_add_text (reply_tree, tvb, offset-4, 4,
722         "Reply status: %s",
723         val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
724
725     }
726
727   nr_seq = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
728
729   for (i = 1; i <= nr_seq; i++)
730     {
731
732       context_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
733       if (tree)
734         {
735           proto_tree_add_text (reply_tree, tvb, offset -4, 4,
736                                "Context id: %u", context_id);
737         }
738
739       sequence_length = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
740       if (tree)
741       {
742           proto_tree_add_text (reply_tree, tvb, offset- 4,
743                                4, "Sequence length: %u", sequence_length);
744       }
745
746       offset += sequence_length;
747       if (tree)
748       {
749           if (sequence_length > 0)
750             {
751               proto_tree_add_text (reply_tree, tvb, offset - sequence_length,
752                                    sequence_length,
753                                    "Sequence data: <not shown>");
754             }
755       }
756
757     }                           /* for */
758
759   dissect_reply_body(tvb, offset, pinfo, reply_tree, stream_is_big_endian,
760     reply_status);
761 }
762
763 static void
764 dissect_giop_cancel_request (tvbuff_t * tvb, packet_info * pinfo,
765                         proto_tree * tree, proto_tree * clnp_tree,
766                         MessageHeader * header, gboolean stream_is_big_endian)
767 {
768   u_int offset = 0;
769   guint32 request_id;
770   proto_tree *cancel_request_tree = NULL;
771   proto_item *tf;
772
773   if (tree)
774     {
775       tf = proto_tree_add_text (tree, tvb, offset,
776                                 tvb_length (tvb),
777                                 "General Inter-ORB Protocol CancelRequest");
778       if (cancel_request_tree == NULL)
779         {
780           cancel_request_tree = proto_item_add_subtree (tf, ett_giop_cancel_request);
781
782         }
783     }
784
785   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
786   if (check_col(pinfo->fd, COL_INFO))
787     {
788       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
789     }
790   if (tree)
791     {
792       proto_tree_add_text (cancel_request_tree, tvb, offset-4, 4,
793                            "Request id: %u", request_id);
794     }
795
796
797 }
798
799 /**  The formats for GIOP 1.0 and 1.1 Request messages are defined
800  *   in section 15.4.2.1 of the CORBA 2.4 specification.
801  *
802  *   struct RequestHeader{
803  *          IOP::ServiceContextList   service_context;
804  *          unsigned long             request_id;
805  *          boolean                   response_expected;
806  *          octet                     reserved[3];  // Only in GIOP 1.1
807  *          sequence<octet>           object_key;
808  *          string                    operation;
809  *          CORBA::OctetSeq           requesting_principal;
810  *   }
811  */
812 static void
813 dissect_giop_request_1_1 (tvbuff_t * tvb, packet_info * pinfo,
814                         proto_tree * tree, proto_tree * clnp_tree,
815                         MessageHeader * header, gboolean stream_is_big_endian)
816 {
817   guint32 offset = 0;
818   guint32 nr_seq = 0;
819   guint32 context_id;
820   guint32 sequence_length;
821   guint32 request_id;
822   guint32 len = 0;
823   gchar *object_key = NULL;
824   gchar *operation = NULL;
825   gchar *requesting_principal = NULL;
826   guint8 response_expected;
827   gchar *reserved = NULL;
828   proto_tree *request_tree = NULL;
829   proto_item *tf;
830   int i;
831
832
833   if (tree)
834     {
835       tf = proto_tree_add_text (tree, tvb, offset,
836                                 tvb_length (tvb),
837                                 "General Inter-ORB Protocol Request");
838       if (request_tree == NULL)
839         {
840           request_tree = proto_item_add_subtree (tf, ett_giop_request);
841
842         }
843     }
844
845   nr_seq = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
846
847   for (i = 1; i <= nr_seq; i++)
848     {
849
850       context_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
851       if (tree)
852         {
853           proto_tree_add_text (request_tree, tvb, offset-4, 4,
854                                "Context id: %u", context_id);
855         }
856
857        sequence_length = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
858        if(tree)
859         {
860            proto_tree_add_text (request_tree, tvb, offset-4, 4, 
861                                 "Sequence length: %u", sequence_length);
862         }
863
864         offset +=  sequence_length;
865         if (sequence_length > 0)
866         {
867               proto_tree_add_text (request_tree, tvb, offset - sequence_length,
868                                    sequence_length,
869                                    "Sequence data: <not shown>");
870         }
871         
872
873     } /* for */
874
875   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
876   if (check_col(pinfo->fd, COL_INFO))
877     {
878       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
879     }
880   if (tree)
881     {
882       proto_tree_add_text (request_tree, tvb, offset-4, 4,
883                            "Request id: %u", request_id);
884     }
885
886   response_expected = tvb_get_guint8( tvb, offset );
887   offset += 1;
888   if (check_col(pinfo->fd, COL_INFO))
889     {
890       col_append_fstr(pinfo->fd, COL_INFO, " (%s)",
891                 response_expected ? "two-way" : "one-way");
892     }
893   if (tree)
894     {
895       proto_tree_add_text (request_tree, tvb, offset-1, 1,
896                            "Response expected: %u", response_expected);
897     }
898
899   if( header->GIOP_version.minor > 0)
900   {
901      get_CDR_octet_seq( tvb, &reserved, &offset, 3);
902      if (tree)
903        {
904          proto_tree_add_text (request_tree, tvb, offset-3, 3,
905                            "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
906        }
907   }
908
909   /* Length of object_key sequence */
910   len = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
911
912   if(tree)
913   {
914          proto_tree_add_text (request_tree, tvb, offset-4, 4,
915          /**/                 "Object Key length: %u", len);
916   } 
917
918   if( len > 0)
919   {
920        get_CDR_octet_seq(tvb, &object_key, &offset, len);
921        printable_string( object_key, len );
922
923        if(tree)
924        {
925          proto_tree_add_text (request_tree, tvb, offset - len, len,
926          /**/                 "Object Key: %s", object_key);
927
928        }
929   } 
930
931   /* length of operation string */ 
932   len = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
933   if(tree)
934   {
935          proto_tree_add_text (request_tree, tvb, offset -4, 4,
936          /**/                 "Operation length: %u", len);
937   } 
938
939   if( len > 0)
940   {
941        get_CDR_octet_seq(tvb, &operation, &offset, len);
942        if (check_col(pinfo->fd, COL_INFO))
943        {
944          col_append_fstr(pinfo->fd, COL_INFO, ": %s", operation);
945        }
946        if(tree)
947        {
948          proto_tree_add_text (request_tree, tvb, offset - len, len,
949          /**/                 "Operation: %s", operation);
950
951        }
952   }
953
954   /* length of requesting_principal string */ 
955   len = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
956   if(tree)
957   {
958          proto_tree_add_text (request_tree, tvb, offset-4, 4,
959          /**/                 "Requesting Principal Length: %u", len);
960   } 
961
962   if( len > 0)
963   {
964        get_CDR_octet_seq(tvb, &requesting_principal, &offset, len);
965        if(tree)
966        {
967          proto_tree_add_text (request_tree, tvb, offset - len, len, 
968          /**/                 "Requesting Principal: %s", requesting_principal);
969
970        }
971   }
972
973   g_free( object_key );
974   g_free( operation );
975   g_free( requesting_principal );
976 }
977
978 /**  The format of a GIOP 1.2 RequestHeader message is 
979  *   (CORBA 2.4, sec. 15.4.2):
980  *
981  *   struct RequestHeader_1_2 {
982  *       unsigned long request_id;
983  *       octet response_flags;
984  *       octet reserved[3];
985  *       TargetAddress target;
986  *       string operation;
987  *       IOP::ServiceContextList service_context;
988  *       // requesting_principal not in GIOP 1.2
989  *   };
990  */
991 static void
992 dissect_giop_request_1_2 (tvbuff_t * tvb, packet_info * pinfo,
993                         proto_tree * tree, proto_tree * clnp_tree,
994                         MessageHeader * header, gboolean stream_is_big_endian)
995 {
996   guint32 offset = 0;
997   guint32 request_id;
998   guint32 len = 0;
999   guint8 response_flags;
1000   gchar *reserved = NULL;
1001   gchar *operation = NULL;
1002   proto_tree *request_tree = NULL;
1003   proto_item *tf;
1004
1005   if (tree)
1006     {
1007       tf = proto_tree_add_text (tree, tvb, offset,
1008                                 tvb_length (tvb),
1009                                 "General Inter-ORB Protocol Request");
1010       if (request_tree == NULL)
1011         {
1012           request_tree = proto_item_add_subtree (tf, ett_giop_reply);
1013
1014         }
1015     }
1016
1017   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
1018   if (check_col(pinfo->fd, COL_INFO))
1019     {
1020       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
1021     }
1022   if (request_tree)
1023     {
1024       proto_tree_add_text (request_tree, tvb, offset-4, 4,
1025                            "Request id: %u", request_id);
1026     }
1027
1028   response_flags = tvb_get_guint8( tvb, offset );
1029   offset += 1;
1030   if (request_tree)
1031     {
1032       proto_tree_add_text (request_tree, tvb, offset-1, 1,
1033                            "Response flags: %s (%u)",
1034                                 match_strval(response_flags, sync_scope),  
1035                                 response_flags);
1036     }
1037
1038   get_CDR_octet_seq( tvb, &reserved, &offset, 3);
1039   if (request_tree)
1040    {
1041      proto_tree_add_text (request_tree, tvb, offset-3, 3,
1042            "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
1043    }
1044
1045   dissect_target_address(tvb, &offset, request_tree, header, stream_is_big_endian);
1046
1047   /* length of operation string */ 
1048   len = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
1049   if(tree)
1050   {
1051          proto_tree_add_text (request_tree, tvb, offset -4, 4,
1052          /**/                 "Operation length: %u", len);
1053   } 
1054
1055   if( len > 0)
1056   {
1057        get_CDR_octet_seq(tvb, &operation, &offset, len);
1058        if (check_col(pinfo->fd, COL_INFO))
1059        {
1060          col_append_fstr(pinfo->fd, COL_INFO, ": %s", operation);
1061        }
1062        if(request_tree)
1063        {
1064          proto_tree_add_text (request_tree, tvb, offset - len, len,
1065          /**/                 "Operation: %s", operation);
1066
1067        }
1068
1069   }
1070   g_free(reserved);
1071 }
1072
1073 static void
1074 dissect_giop_locate_request( tvbuff_t * tvb, packet_info * pinfo,
1075                         proto_tree * tree, MessageHeader * header,
1076                         gboolean stream_is_big_endian)
1077 {
1078   guint32 offset = 0;
1079   guint32 request_id;
1080   guint32 len = 0;
1081   gchar *object_key = NULL;
1082   proto_tree *locate_request_tree = NULL;
1083   proto_item *tf;
1084
1085   if (tree)
1086     {
1087       tf = proto_tree_add_text (tree, tvb, offset,
1088                                 tvb_length (tvb),
1089                                 "General Inter-ORB Locate Request");
1090       if (locate_request_tree == NULL)
1091         {
1092           locate_request_tree = proto_item_add_subtree (tf, ett_giop_locate_request);
1093
1094         }
1095     }
1096
1097   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
1098   if (check_col(pinfo->fd, COL_INFO))
1099     {
1100       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
1101     }
1102   if (locate_request_tree)
1103     {
1104       proto_tree_add_text (locate_request_tree, tvb, offset-4, 4,
1105                            "Request id: %u", request_id);
1106     }
1107
1108   if(header->GIOP_version.minor < 2)
1109   {
1110         len = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
1111         get_CDR_octet_seq(tvb, &object_key, &offset, len);
1112
1113         if(locate_request_tree)
1114         {
1115
1116            proto_tree_add_text (locate_request_tree, tvb, offset-len, len,
1117                            "Object Key: %s", object_key);
1118
1119
1120         }
1121
1122   }
1123   else     // GIOP 1.2 and higher
1124   {
1125       dissect_target_address(tvb, &offset, locate_request_tree, header,
1126                              stream_is_big_endian);
1127
1128   }
1129   g_free( object_key );  
1130 }
1131
1132 static void
1133 dissect_giop_locate_reply( tvbuff_t * tvb, packet_info * pinfo,
1134                         proto_tree * tree, MessageHeader * header,
1135                         gboolean stream_is_big_endian)
1136 {
1137   guint32 offset = 0;
1138   guint32 request_id;
1139   guint32 locate_status;
1140   proto_tree *locate_reply_tree = NULL;
1141   proto_item *tf;
1142
1143   if (tree)
1144     {
1145       tf = proto_tree_add_text (tree, tvb, offset,
1146                                 tvb_length (tvb),
1147                                 "General Inter-ORB Locate Reply");
1148       if (locate_reply_tree == NULL)
1149         {
1150           locate_reply_tree = proto_item_add_subtree (tf, ett_giop_locate_reply);
1151
1152         }
1153     }
1154
1155   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
1156   if (check_col(pinfo->fd, COL_INFO))
1157     {
1158       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
1159     }
1160   if (locate_reply_tree)
1161     {
1162       proto_tree_add_text (locate_reply_tree, tvb, offset-4, 4,
1163                            "Request id: %u", request_id);
1164     }
1165
1166   locate_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
1167   if (locate_reply_tree)
1168     {
1169       proto_tree_add_text (locate_reply_tree, tvb, offset-4, 4,
1170                            "Locate status: %s", 
1171                            match_strval(locate_status, giop_locate_status_types)
1172                            );
1173                                    
1174     }
1175
1176 }
1177
1178 static void
1179 dissect_giop_fragment( tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
1180                         MessageHeader * header, gboolean stream_is_big_endian)
1181 {
1182   guint32 offset = 0;
1183   guint32 request_id;
1184   proto_tree *fragment_tree = NULL;
1185   proto_item *tf;
1186
1187   if (tree)
1188     {
1189       tf = proto_tree_add_text (tree, tvb, offset,
1190                                 tvb_length (tvb),
1191                                 "General Inter-ORB Fragment");
1192       if (fragment_tree == NULL)
1193         {
1194           fragment_tree = proto_item_add_subtree (tf, ett_giop_fragment);
1195
1196         }
1197     }
1198
1199   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
1200   if (check_col(pinfo->fd, COL_INFO))
1201     {
1202       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
1203     }
1204   if (fragment_tree )
1205     {
1206       proto_tree_add_text (fragment_tree, tvb, offset-4, 4,
1207                            "Request id: %u", request_id);
1208     }
1209
1210                                    
1211 }
1212
1213
1214 /* main entry point */
1215 static gboolean
1216 dissect_giop (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
1217 {
1218   u_int offset = 0;
1219   MessageHeader header;
1220   tvbuff_t *giop_header_tvb;
1221   tvbuff_t *payload_tvb;
1222
1223   proto_tree *clnp_tree = NULL;
1224   proto_item *ti;
1225   u_int message_size;
1226   u_int minor_version;
1227   gboolean stream_is_big_endian;
1228
1229   if( !proto_is_protocol_enabled( proto_giop ))
1230           return FALSE; /* GIOP has been disabled */
1231
1232   pinfo->current_proto = "GIOP";
1233
1234   /* check magic number and version */
1235
1236
1237   /*define END_OF_GIOP_MESSAGE (offset - first_offset - GIOP_HEADER_SIZE) */
1238
1239   if (tvb_length_remaining(tvb, 0) < GIOP_HEADER_SIZE)
1240     {
1241       /* Not enough data captured to hold the GIOP header; don't try
1242          to interpret it as GIOP. */
1243       return FALSE;
1244     }
1245
1246   giop_header_tvb = tvb_new_subset (tvb, 0, GIOP_HEADER_SIZE, -1);
1247   payload_tvb = tvb_new_subset (tvb, GIOP_HEADER_SIZE, -1, -1);
1248
1249   /*  memcpy(&header, &pd[offset], sizeof(header)); */
1250   tvb_memcpy (giop_header_tvb, (guint8 *)&header, 0, sizeof (header));
1251
1252   if (memcmp (header.magic, GIOP_MAGIC, sizeof (header.magic)) != 0)
1253     {
1254       /* Not a GIOP message. */
1255       return FALSE;
1256     }
1257
1258   if (check_col (pinfo->fd, COL_PROTOCOL))
1259     {
1260       col_set_str (pinfo->fd, COL_PROTOCOL, "GIOP");
1261     }
1262
1263   if (header.GIOP_version.major != GIOP_MAJOR ||
1264       ((minor_version = header.GIOP_version.minor) > GIOP_MINOR))
1265     {
1266       /* Bad version number; should we note that and dissect the rest
1267          as data, or should we return FALSE on the theory that it
1268          might have been some other packet that happened to begin with
1269          "GIOP"?  We shouldn't do *both*, so we return TRUE, for now.
1270          If we should return FALSE, we should do so *without* setting
1271          the "Info" column, *without* setting the "Protocol" column,
1272          and *without* adding anything to the protocol tree. */
1273       if (check_col (pinfo->fd, COL_INFO))
1274         {
1275           col_add_fstr (pinfo->fd, COL_INFO, "Version %u.%u",
1276                         header.GIOP_version.major, header.GIOP_version.minor);
1277         }
1278       if (tree)
1279         {
1280           ti = proto_tree_add_item (tree, proto_giop, tvb, 0,
1281                                     tvb_length (tvb), FALSE);
1282           clnp_tree = proto_item_add_subtree (ti, ett_giop);
1283           proto_tree_add_text (clnp_tree, giop_header_tvb, 0,
1284                                tvb_length (giop_header_tvb),
1285                                "Version %u.%u not supported",
1286                                header.GIOP_version.major,
1287                                header.GIOP_version.minor);
1288         }
1289       dissect_data (payload_tvb, 0, pinfo, tree);
1290       return TRUE;
1291     }
1292
1293   stream_is_big_endian = is_big_endian (&header);
1294
1295   if (stream_is_big_endian)
1296     message_size = pntohl (&header.message_size);
1297   else
1298     message_size = pletohl (&header.message_size);
1299
1300   if (tree)
1301     {
1302       ti = proto_tree_add_item (tree, proto_giop, tvb, 0, 12, FALSE);
1303       clnp_tree = proto_item_add_subtree (ti, ett_giop);
1304       proto_tree_add_text (clnp_tree, giop_header_tvb, offset, 4,
1305                            "Magic number: %s", GIOP_MAGIC);
1306       proto_tree_add_text (clnp_tree, giop_header_tvb, 4, 2,
1307                            "Version: %u.%u",
1308                            header.GIOP_version.major,
1309                            header.GIOP_version.minor);
1310       switch (minor_version)
1311         {
1312         case 2:
1313         case 1:
1314           proto_tree_add_text (clnp_tree, giop_header_tvb, 6, 1,
1315                                "Flags: 0x%02x (%s %s)",
1316                                header.flags,
1317                                (stream_is_big_endian) ? "big-endian" : "little-endian",
1318                                (header.flags & 0x02) ? " fragment" : "");
1319           break;
1320         case 0:
1321           proto_tree_add_text (clnp_tree, giop_header_tvb, 6, 1,
1322                                "Byte ordering: %s-endian",
1323                                (stream_is_big_endian) ? "big" : "little");
1324           break;
1325         default:
1326           break;
1327         }                       /* minor_version */
1328
1329       proto_tree_add_uint_format (clnp_tree,
1330                                   hf_giop_message_type,
1331                                   giop_header_tvb, 7, 1,
1332                                   header.message_type,
1333                                   "Message type: %s", match_strval(header.message_type, giop_message_types));
1334
1335       proto_tree_add_uint (clnp_tree,
1336                            hf_giop_message_size,
1337                            giop_header_tvb, 8, 4, message_size);
1338
1339     }                           /* tree */
1340
1341   if (check_col (pinfo->fd, COL_INFO)) 
1342   { 
1343       col_add_fstr (pinfo->fd, COL_INFO, "GIOP %u.%u %s",
1344                     header.GIOP_version.major, header.GIOP_version.minor,
1345                     match_strval(header.message_type, giop_message_types));
1346   }
1347
1348   switch (header.message_type)
1349     {
1350
1351     case Request:
1352       if(header.GIOP_version.minor < 2)
1353       {
1354            dissect_giop_request_1_1 (payload_tvb, pinfo, tree, clnp_tree,
1355                                      &header, stream_is_big_endian);
1356       }
1357       else
1358       {    
1359            dissect_giop_request_1_2 (payload_tvb, pinfo, tree, clnp_tree,
1360                                      &header, stream_is_big_endian);
1361       }
1362       
1363       break;
1364
1365
1366     case Reply:
1367       if(header.GIOP_version.minor < 2)
1368         {
1369            dissect_giop_reply (payload_tvb, pinfo, tree, clnp_tree, &header,
1370                                stream_is_big_endian);
1371         }
1372       else
1373         {
1374            dissect_giop_reply_1_2 (payload_tvb, pinfo, tree, clnp_tree,
1375                                    &header, stream_is_big_endian);
1376         }
1377       break;
1378     case CancelRequest:
1379         dissect_giop_cancel_request(payload_tvb, pinfo, tree, clnp_tree,
1380                                     &header, stream_is_big_endian);
1381         break;
1382     case LocateRequest:
1383         dissect_giop_locate_request(payload_tvb, pinfo, tree, &header,
1384                                     stream_is_big_endian);
1385         break;
1386     case LocateReply:
1387         dissect_giop_locate_reply(payload_tvb, pinfo, tree, &header,
1388                                   stream_is_big_endian);
1389         break;
1390     case Fragment:
1391         dissect_giop_fragment(payload_tvb, pinfo, tree, &header,
1392                               stream_is_big_endian);
1393         break;  
1394     default:
1395       break;
1396
1397     }                           /* switch message_type */
1398     return TRUE;
1399 }
1400
1401 void
1402 proto_register_giop (void)
1403 {
1404   static hf_register_info hf[] = {
1405     {
1406      &hf_giop_message_type,
1407      {
1408       "Message type", "giop.type",
1409       FT_UINT8, BASE_DEC, NULL, 0x0, ""}
1410      }
1411     ,
1412     {
1413      &hf_giop_message_size,
1414      {
1415       "Message size", "giop.len",
1416       FT_UINT32, BASE_DEC, NULL, 0x0, ""}
1417      }
1418     ,
1419   };
1420   static gint *ett[] = {
1421     &ett_giop,
1422     &ett_giop_reply,
1423     &ett_giop_request,
1424     &ett_giop_cancel_request,
1425     &ett_giop_locate_request,
1426     &ett_giop_locate_reply,
1427     &ett_giop_fragment
1428   };
1429   proto_giop = proto_register_protocol("General Inter-ORB Protocol", "GIOP",
1430                                        "giop");
1431   proto_register_field_array (proto_giop, hf, array_length (hf));
1432   proto_register_subtree_array (ett, array_length (ett));
1433 }
1434
1435 void
1436 proto_reg_handoff_giop (void)
1437 {
1438   heur_dissector_add ("tcp", dissect_giop, proto_giop);
1439 }