Created a new protocol tree implementation and a new display filter
[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  *
6  * $Id: packet-giop.c,v 1.3 1999/07/07 22:51:43 gram Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
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  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
36 #endif
37
38 #include <string.h>
39 #include <ctype.h>
40 #include <glib.h>
41 #include "packet.h"
42
43 /*
44  * GIOP / IIOP types definition - OMG CORBA 2.x / GIOP 1.[01]
45  * See OMG WEB site <http://www.omg.org> - CORBA+IIOP 2.2 (98-02-01.ps)
46  *
47  * Notes on mapping:
48  *
49  * <sequence> : unsigned int (# elts) + elements
50  * <string>   : unsigned int (string length) + length characters (with '\0')
51  * <enum>     : unsigned int (from 0 to n)
52  */
53
54 #define GIOP_MAGIC       "GIOP"
55 #define GIOP_MAJOR       1
56 #define GIOP_MINOR       1
57
58 #define GIOP_HEADER_SIZE 12
59
60 typedef struct OctetSequence{
61   u_int         sequence_length;
62   u_char        sequence_data[1];               /* of length bytes */
63 } OctetSequence;
64
65 typedef OctetSequence Principal;
66 typedef OctetSequence String;
67
68 /* 
69  * Some structures that contain sequences can not be directly used 
70  * (alignment problem on 64 bit architectures)
71  */
72
73 typedef struct ServiceContext {
74   u_int         context_id;
75   OctetSequence context_data;
76 } ServiceContext;
77
78 typedef struct ServiceContextList{
79   u_int           nr_context;
80   ServiceContext  service_context[1];           /* nr_context elements */
81 } ServiceContextList;
82
83 typedef enum MsgType {
84   Request,
85   Reply,
86   CancelRequest, 
87   LocateRequest,
88   LocateReply, 
89   CloseConnection,
90   MessageError,
91   Fragment                                      /* GIOP 1.1 only */
92 } MsgType;
93
94 typedef struct Version {
95   u_char        major;
96   u_char        minor;
97 } Version;
98
99 typedef struct MessageHeader {
100   char          magic[4];
101   Version       GIOP_version;
102   u_char        flags;                          /* byte_order in 1.0 */
103   u_char        message_type;
104   u_int         message_size;
105 } MessageHeader;
106
107 typedef struct RequestHeader_1_0 {
108   /* ServiceContextList service_context;*/
109   u_int         request_id;
110   u_char        response_expected;
111   OctetSequence object_key;
112   /* String     operation;              */
113   /* Principal  requesting_principal;   */
114 } RequestHeader_1_0;
115
116 typedef struct RequestHeader_1_1 {
117   /* ServiceContextList service_context;*/
118   u_int         request_id;
119   u_char        response_expected;
120   u_char        reserved[3];
121   OctetSequence object_key;
122   /* String     operation;              */
123   /* Principal  requesting_principal;   */
124 } RequestHeader_1_1;
125
126 typedef enum ReplyStatusType {
127   NO_EXCEPTION, 
128   USER_EXCEPTION, 
129   SYSTEM_EXCEPTION, 
130   LOCATION_FORWARD
131 } ReplyStatusType;
132
133 typedef struct ReplyHeader {
134   /* ServiceContext service_context;    */
135   u_int         request_id;
136   u_int         reply_status;
137 } ReplyHeader;
138
139 typedef struct SystemExceptionReplyBody {
140   String        exception_id; 
141   u_int         minor_code_value;
142   u_int         completion_status;
143 } SystemExceptionReplyBody;
144
145 typedef struct CancelRequestHeader {
146   u_int         request_id;
147 } CancelRequestHeader;
148
149 typedef struct LocateRequestHeader {
150   u_int         request_id;
151   OctetSequence object_key;
152 } LocateRequestHeader;
153
154 typedef enum LocateStatusType {
155   UNKNOWN_OBJECT, 
156   OBJECT_HERE, 
157   OBJECT_FORWARD
158 } LocateStatusType;
159
160 typedef struct LocateReplyHeader {
161   u_int         request_id;
162   u_int         locate_status;
163 } LocateReplyHeader;
164
165
166 u_char *print_object_key(int length, u_char *from) 
167 {
168 #define MAX_OBJECT_KEY_LENGTH 64
169   static u_char buffer[MAX_OBJECT_KEY_LENGTH];
170   u_char *to = buffer;
171   int i = 0;
172   length = MIN(MAX_OBJECT_KEY_LENGTH - 3, length);
173   *to++ = '"';
174   while(i++ < length) {
175     *to = (isprint(*from)) ? *from : '.'; 
176     to++;
177     from++;
178   }  
179   *to++ = '"';
180   *to = '\0';
181   return buffer;
182 }
183
184 /* main entry point */
185
186 void dissect_giop(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) 
187 {
188
189   MessageHeader header;
190   proto_tree *clnp_tree = NULL;
191   proto_item *ti;
192   u_char response_expected = 0;
193   u_int first_offset = offset;
194   u_int big_endian = FALSE;
195   u_int request_id = 0;
196   u_int message_size;
197   u_int minor_version;
198   u_int context_id;
199   u_int reply_status;
200   u_int locate_status;
201   u_int sequence_length;
202   u_int nr_seq;
203   RequestHeader_1_1 request_1_1;
204   RequestHeader_1_0 request_1_0;
205   ReplyHeader reply;
206   LocateReplyHeader locate_rep;
207   LocateRequestHeader locate_req;
208   int i;
209
210 #define END_OF_GIOP_MESSAGE (offset - first_offset - GIOP_HEADER_SIZE)
211
212   if (fd->cap_len < offset + GIOP_HEADER_SIZE) {
213     dissect_data(pd, offset, fd, tree);
214     return;
215   }
216
217   /* avoid alignment problem */
218
219   memcpy(&header, &pd[offset], sizeof(header));
220
221   /* check magic number and version */
222
223   if (memcmp(header.magic, GIOP_MAGIC, sizeof(header.magic)) != 0) {
224     dissect_data(pd, offset, fd, tree);
225     return;
226   }
227
228   if (header.GIOP_version.major != GIOP_MAJOR ||
229       ((minor_version = header.GIOP_version.minor) >  GIOP_MINOR)) {
230     dissect_data(pd, offset, fd, tree);
231     return;
232   }
233
234   switch(minor_version) {
235     case 1  :
236       if (header.flags & 0x01)
237         big_endian = FALSE;
238       else
239         big_endian = TRUE;
240       break;
241     case 0  :
242       if (header.flags)
243         big_endian = FALSE;
244       else
245         big_endian = TRUE;
246       break;
247     default :
248       break;
249   }
250   
251   if (big_endian)
252     message_size = pntohl(&header.message_size);
253   else
254     message_size = pletohl(&header.message_size);
255
256   if (check_col(fd, COL_PROTOCOL)) {
257     col_add_str(fd, COL_PROTOCOL, "GIOP");
258   }
259
260   if (tree) {
261     ti = proto_tree_add_text(tree, offset, 
262                           GIOP_HEADER_SIZE + message_size,
263                           "General Inter-ORB Protocol");
264     clnp_tree = proto_item_add_subtree(ti, ETT_GIOP);
265     proto_tree_add_text(clnp_tree, offset,      4,
266                      "Magic number: %s", GIOP_MAGIC);
267     proto_tree_add_text(clnp_tree, offset +  4, 2, 
268                      "Version: %d.%d", 
269                      header.GIOP_version.major,
270                      header.GIOP_version.minor);
271     switch(minor_version) {
272       case 1  :
273         proto_tree_add_text(clnp_tree, offset +  6, 1, 
274                          "Flags: 0x%02x (%s%s)", 
275                          header.flags,
276                          (big_endian) ? "little" : "big",
277                          (header.flags & 0x02) ? " fragment" : "");
278         break;
279       case 0  :
280         proto_tree_add_text(clnp_tree, offset +  6, 1, 
281                          "Byte ordering: %s endian",
282                          (big_endian) ? "little" : "big");
283         break;
284       default :
285         break;
286     } /* minor_version */
287
288     proto_tree_add_text(clnp_tree, offset +  7, 1, 
289                      "Message type: %s",
290                      (header.message_type == Request) ? "Request" :
291                      (header.message_type == Reply) ? "Reply" :
292                      (header.message_type == CancelRequest) ? "CancelRequest" :
293                      (header.message_type == LocateRequest) ? "LocateRequest" :
294                      (header.message_type == LocateReply) ? "LocateReply" :
295                      (header.message_type == CloseConnection) ? "CloseConnection" :
296                      (header.message_type == MessageError) ? "MessageError" :
297                      (header.message_type == Fragment) ? "Fragment" : "?");
298
299     proto_tree_add_text(clnp_tree, offset +  8, 4, 
300                      "Message size: %d", message_size);
301
302   } /* tree */
303
304   offset += GIOP_HEADER_SIZE;
305
306   if (fd->cap_len < offset + message_size) {
307     dissect_data(pd, offset, fd, tree);
308     return;
309   }
310
311   /* skip service_context in Request/Reply messages */
312
313   switch(header.message_type) {
314
315     case Request:
316     case Reply :
317
318       nr_seq = (big_endian) ? pntohl(&pd[offset]) : pletohl(&pd[offset]);
319
320       offset += sizeof(nr_seq);
321
322       for (i = 0 ; i < nr_seq ; i++) {
323
324         if (big_endian) {       
325           context_id = pntohl(&pd[offset]);
326           sequence_length = pntohl(&pd[offset + sizeof(context_id)]);
327         }
328         else {
329           context_id = pletohl(&pd[offset]);
330           sequence_length = pletohl(&pd[offset + sizeof(context_id)]);
331         }
332
333         if (tree) {
334           proto_tree_add_text(clnp_tree, offset, sizeof(context_id),
335                            "Context id: %d", context_id);
336           proto_tree_add_text(clnp_tree, offset + sizeof(context_id),
337                            sizeof(sequence_length),
338                            "Sequence length: %d", sequence_length);
339           proto_tree_add_text(clnp_tree,
340                            offset + 
341                            sizeof(context_id) + sizeof(sequence_length),
342                            sequence_length,
343                            "Sequence data: <not shown>");
344         }
345
346         offset += sizeof(context_id) + sizeof(sequence_length) + sequence_length;
347         offset += (sequence_length %4) ? 4 - (sequence_length%4) : 0 ;
348
349       } /* for */
350
351     default :
352       break;
353
354   } /* switch message_type */
355
356   /* decode next parts according to message type */
357
358   switch(header.message_type) {
359
360     case Request:
361
362       switch(minor_version) {
363         case 1  :
364           memcpy(&request_1_1, &pd[offset], sizeof(request_1_1));
365           response_expected = request_1_1.response_expected;
366           request_id = (big_endian)? pntohl(&request_1_1.request_id) :
367             pletohl(&request_1_1.request_id);
368           if (tree) {
369             proto_tree_add_text(clnp_tree, offset, sizeof(request_id),
370                              "Request id: %d", request_id);
371             proto_tree_add_text(clnp_tree, offset + sizeof(request_id),
372                              sizeof(request_1_1.response_expected),
373                              "Response expected: %d", 
374                              response_expected);
375             proto_tree_add_text(clnp_tree, offset + sizeof(request_id) +
376                              sizeof(request_1_1.response_expected),
377                              3,
378                              "Reserved");
379           }
380           offset += sizeof(request_id) + 
381             sizeof(request_1_1.response_expected) + 3;
382           break;
383         case 0  :
384           memcpy(&request_1_0, &pd[offset], sizeof(request_1_0));
385           response_expected = request_1_0.response_expected;
386           request_id = (big_endian)? pntohl(&request_1_0.request_id) :
387             pletohl(&request_1_0.request_id);
388           if (tree) {
389             proto_tree_add_text(clnp_tree, offset, sizeof(request_id),
390                              "Request id: %d", request_id);
391             proto_tree_add_text(clnp_tree, offset + sizeof(request_id),
392                              sizeof(request_1_0.response_expected),
393                              "Response expected: %d", 
394                              response_expected);
395           }
396
397           offset += sizeof(request_id) + 
398             sizeof(request_1_0.response_expected);
399           break;
400         default :
401           break;
402       }
403
404       /* strange thing here with some ORBs/IIOP1.0 ? */
405       if ((offset - first_offset) % 4)
406         offset += 4 - (offset - first_offset)%4;
407
408       /* object_key */
409
410       sequence_length = (big_endian) ? 
411         pntohl(&pd[offset]) : pletohl(&pd[offset]);
412
413       if (tree) {
414         proto_tree_add_text(clnp_tree, offset, sizeof(sequence_length),
415                          "Object key length: %d", sequence_length);
416         proto_tree_add_text(clnp_tree, offset + sizeof(sequence_length),
417                          sequence_length,
418                          "Object key: %s",
419                          print_object_key(sequence_length, 
420                            (u_char *)&pd[offset + sizeof(sequence_length)]));
421       }
422
423       /* operation & requesting_principal */
424
425       offset += sizeof(sequence_length) + sequence_length;
426       offset += (sequence_length %4) ? 4 - (sequence_length%4) : 0 ;
427
428       sequence_length = (big_endian) ? 
429         pntohl(&pd[offset]) : pletohl(&pd[offset]);
430
431       if (sequence_length > message_size) {
432         dissect_data(pd, offset, fd, tree);
433         return;
434       }
435        
436       if (tree) {
437         proto_tree_add_text(clnp_tree, offset, sizeof(sequence_length),
438                          "Operation length: %d", sequence_length);
439         proto_tree_add_text(clnp_tree, offset + sizeof(sequence_length), 
440                          sequence_length,
441                          "Operation: %s",
442                          &pd[offset+sizeof(sequence_length)]);
443         proto_tree_add_text(clnp_tree, offset +
444                          sizeof(sequence_length)+ sequence_length,
445                          message_size - END_OF_GIOP_MESSAGE - 
446                          sizeof(sequence_length) - sequence_length,
447                          "Requesting principal: <not shown>");
448       }
449
450       if (check_col(fd, COL_INFO)) {
451         col_add_fstr(fd, COL_INFO, "Request %s %d: %s",
452                 response_expected ? "two-way" : "one-way" ,
453                 request_id,
454                 &pd[offset+sizeof(sequence_length)]);
455       }
456
457       break;
458
459     case Reply :
460
461       memcpy(&reply, &pd[offset], sizeof(reply));
462       request_id =  (big_endian) ? 
463         pntohl(&reply.request_id) : pletohl(&reply.request_id);
464       reply_status = (big_endian) ? 
465         pntohl(&reply.reply_status) : pletohl(&reply.reply_status);
466
467       if (tree) {
468         proto_tree_add_text(clnp_tree, offset, sizeof(request_id),
469                          "Request id: %d", request_id);
470         proto_tree_add_text(clnp_tree, offset + sizeof(request_id), 
471                          sizeof(reply_status),
472                          "Reply status: %s",
473                          reply_status == NO_EXCEPTION ? "no exception" :
474                          reply_status == USER_EXCEPTION ? "user exception" :
475                          reply_status == SYSTEM_EXCEPTION ? "system exception" :
476                          reply_status == LOCATION_FORWARD ? "location forward" :
477                          "?");
478       }
479
480       if (check_col(fd, COL_INFO)) {
481         col_add_fstr(fd, COL_INFO, "Reply %d: %s",
482                 request_id,
483                 reply_status == NO_EXCEPTION ? "no exception" :
484                 reply_status == USER_EXCEPTION ? "user exception" :
485                 reply_status == SYSTEM_EXCEPTION ? "system exception" :
486                 reply_status == LOCATION_FORWARD ? "location forward" :
487                 "?");
488       }
489
490       offset += sizeof(request_id) + sizeof(reply_status);
491
492       if (reply_status == SYSTEM_EXCEPTION) {
493
494         u_int minor_code_value;
495         u_int completion_status;
496
497         sequence_length = (big_endian) ? 
498           pntohl(&pd[offset]) : pletohl(&pd[offset]);
499
500         if (sequence_length > message_size) {
501           dissect_data(pd, offset, fd, tree);
502           return;
503         }
504
505         if (tree) {
506           proto_tree_add_text(clnp_tree, offset, sizeof(sequence_length),
507                            "Exception length: %d", sequence_length);
508           proto_tree_add_text(clnp_tree, offset + sizeof(sequence_length), 
509                            sequence_length,
510                            "Exception id: %s",
511                            &pd[offset+sizeof(sequence_length)]);
512
513         }
514
515         offset += sizeof(sequence_length) + sequence_length;
516
517         minor_code_value = (big_endian) ? 
518           pntohl(&pd[offset]) : pletohl(&pd[offset]);
519         completion_status = (big_endian) ? 
520           pntohl(&pd[offset+sizeof(minor_code_value)]) :
521           pletohl(&pd[offset+sizeof(minor_code_value)]);
522         
523         if (tree) {
524           proto_tree_add_text(clnp_tree, offset, sizeof(minor_code_value),
525                            "Minor code value: %d", minor_code_value);
526           proto_tree_add_text(clnp_tree, offset + sizeof(minor_code_value),
527                            sizeof(completion_status),
528                            "Completion Status: %d",
529                            completion_status);
530           
531         }
532
533       }
534       else if (reply_status == USER_EXCEPTION) {
535
536         sequence_length = (big_endian) ? 
537           pntohl(&pd[offset]) : pletohl(&pd[offset]);
538
539         if (sequence_length > message_size) {
540           dissect_data(pd, offset, fd, tree);
541           return;
542         }
543
544         if (tree) {
545           proto_tree_add_text(clnp_tree, offset, sizeof(sequence_length),
546                            "Exception length: %d", sequence_length);
547           proto_tree_add_text(clnp_tree, offset + sizeof(sequence_length), 
548                            sequence_length,
549                            "Exception id: %s",
550                            &pd[offset+sizeof(sequence_length)]);
551
552         }
553
554         offset += sizeof(sequence_length) + sequence_length;
555
556         sequence_length = (big_endian) ? 
557           pntohl(&pd[offset]) : pletohl(&pd[offset]);
558
559         if (sequence_length > message_size) {
560           dissect_data(pd, offset, fd, tree);
561           return;
562         }
563
564         if (tree && sequence_length) {
565           proto_tree_add_text(clnp_tree, offset, sizeof(sequence_length),
566                            "Exception member length: %d", sequence_length);
567           proto_tree_add_text(clnp_tree, offset + sizeof(sequence_length), 
568                            sequence_length,
569                            "Exception member: %s",
570                            &pd[offset+sizeof(sequence_length)]);
571         }
572
573         offset += sizeof(sequence_length) + sequence_length;
574
575       }
576       else {
577         
578         if (tree) {
579           proto_tree_add_text(clnp_tree, offset,
580                            message_size - END_OF_GIOP_MESSAGE,
581                            "Reply body: <not shown>");
582         }
583
584       } /* reply_status */
585
586       break;
587
588     case LocateRequest :
589
590       memcpy(&locate_req, &pd[offset], sizeof(locate_req));
591       request_id =  (big_endian) ? 
592         pntohl(&locate_req.request_id) : pletohl(&locate_req.request_id);
593
594       sequence_length = (big_endian) ? 
595         pntohl(&pd[offset+sizeof(request_id)]) : 
596         pletohl(&pd[offset+sizeof(request_id)]);
597
598       if (tree) {
599         proto_tree_add_text(clnp_tree, offset, sizeof(request_id),
600                          "Request id: %d", request_id);
601         proto_tree_add_text(clnp_tree, offset + sizeof(request_id), 
602                          sizeof(sequence_length),
603                          "Object key length: %d", sequence_length);
604         offset += sizeof(request_id) + sizeof(sequence_length);
605         proto_tree_add_text(clnp_tree,
606                          offset,
607                          sequence_length,
608                          "Object key: %s", 
609                          print_object_key(sequence_length, 
610                                           (u_char *)&pd[offset]));
611       }
612
613       if (check_col(fd, COL_INFO)) {
614         col_add_fstr(fd, COL_INFO, "LocateRequest %d", request_id);
615       }
616
617       break;
618
619     case LocateReply :
620
621       memcpy(&locate_rep, &pd[offset], sizeof(locate_rep));
622       request_id =  (big_endian) ? 
623         pntohl(&locate_rep.request_id) : pletohl(&locate_rep.request_id);
624       locate_status = (big_endian) ? 
625         pntohl(&locate_rep.locate_status) : pletohl(&locate_rep.locate_status);
626
627       if (tree) {
628         proto_tree_add_text(clnp_tree, offset, sizeof(request_id),
629                          "Request id: %d", request_id);
630         proto_tree_add_text(clnp_tree, offset + sizeof(request_id), 
631                          sizeof(locate_status),
632                          "Locate status: %d", locate_status);
633         offset += sizeof(request_id) + sizeof(locate_status);
634         if (locate_status == OBJECT_FORWARD) {
635           proto_tree_add_text(clnp_tree, offset,
636                            message_size - END_OF_GIOP_MESSAGE,
637                            "Locate reply body: <not shown>");
638         }
639       }
640
641       if (check_col(fd, COL_INFO)) {
642         col_add_fstr(fd, COL_INFO, "LocateReply %d: %s",
643                 request_id, 
644                 (locate_status == UNKNOWN_OBJECT) ? "Unknown object" :
645                 (locate_status == OBJECT_HERE) ? "Object here" :
646                 (locate_status == OBJECT_FORWARD) ? "Object forward" : "?");
647       }
648
649       break;
650
651     case CancelRequest :
652
653       request_id =  (big_endian) ? 
654         pntohl(&pd[offset]) : pletohl(&pd[offset]);
655
656       if (tree) {
657         proto_tree_add_text(clnp_tree, offset, sizeof(request_id),
658                          "Request id: %d", request_id);
659       }
660
661       if (check_col(fd, COL_INFO)) {
662         col_add_fstr(fd, COL_INFO, "CancelRequest %d", request_id);
663       }
664
665       break;
666
667     case CloseConnection :
668       if (check_col(fd, COL_INFO)) {
669         col_add_str(fd, COL_INFO, "CloseConnection");
670       }
671       break;
672
673     case MessageError :
674       if (check_col(fd, COL_INFO)) {
675         col_add_str(fd, COL_INFO, "MessageError");
676       }
677       break;
678
679     case Fragment :
680       if (check_col(fd, COL_INFO)) {
681         col_add_str(fd, COL_INFO, "Fragment");
682       }
683       break;
684
685     default :
686       break;
687
688   } /* switch message_type */
689
690
691   offset = first_offset + GIOP_HEADER_SIZE + message_size;
692
693   if (offset < fd->cap_len) {
694     dissect_data(pd, offset, fd, tree);
695   }
696
697 } /* dissect_giop */
698