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