Note that non-GNU "make"s appear not to be able to build Ethereal, and
[metze/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.2 1999/03/23 03:14:37 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_item(tree, offset, 
262                           GIOP_HEADER_SIZE + message_size,
263                           "General Inter-ORB Protocol");
264     clnp_tree = proto_tree_new();
265     proto_item_add_subtree(ti, clnp_tree, ETT_GIOP);
266     proto_tree_add_item(clnp_tree, offset,      4,
267                      "Magic number: %s", GIOP_MAGIC);
268     proto_tree_add_item(clnp_tree, offset +  4, 2, 
269                      "Version: %d.%d", 
270                      header.GIOP_version.major,
271                      header.GIOP_version.minor);
272     switch(minor_version) {
273       case 1  :
274         proto_tree_add_item(clnp_tree, offset +  6, 1, 
275                          "Flags: 0x%02x (%s%s)", 
276                          header.flags,
277                          (big_endian) ? "little" : "big",
278                          (header.flags & 0x02) ? " fragment" : "");
279         break;
280       case 0  :
281         proto_tree_add_item(clnp_tree, offset +  6, 1, 
282                          "Byte ordering: %s endian",
283                          (big_endian) ? "little" : "big");
284         break;
285       default :
286         break;
287     } /* minor_version */
288
289     proto_tree_add_item(clnp_tree, offset +  7, 1, 
290                      "Message type: %s",
291                      (header.message_type == Request) ? "Request" :
292                      (header.message_type == Reply) ? "Reply" :
293                      (header.message_type == CancelRequest) ? "CancelRequest" :
294                      (header.message_type == LocateRequest) ? "LocateRequest" :
295                      (header.message_type == LocateReply) ? "LocateReply" :
296                      (header.message_type == CloseConnection) ? "CloseConnection" :
297                      (header.message_type == MessageError) ? "MessageError" :
298                      (header.message_type == Fragment) ? "Fragment" : "?");
299
300     proto_tree_add_item(clnp_tree, offset +  8, 4, 
301                      "Message size: %d", message_size);
302
303   } /* tree */
304
305   offset += GIOP_HEADER_SIZE;
306
307   if (fd->cap_len < offset + message_size) {
308     dissect_data(pd, offset, fd, tree);
309     return;
310   }
311
312   /* skip service_context in Request/Reply messages */
313
314   switch(header.message_type) {
315
316     case Request:
317     case Reply :
318
319       nr_seq = (big_endian) ? pntohl(&pd[offset]) : pletohl(&pd[offset]);
320
321       offset += sizeof(nr_seq);
322
323       for (i = 0 ; i < nr_seq ; i++) {
324
325         if (big_endian) {       
326           context_id = pntohl(&pd[offset]);
327           sequence_length = pntohl(&pd[offset + sizeof(context_id)]);
328         }
329         else {
330           context_id = pletohl(&pd[offset]);
331           sequence_length = pletohl(&pd[offset + sizeof(context_id)]);
332         }
333
334         if (tree) {
335           proto_tree_add_item(clnp_tree, offset, sizeof(context_id),
336                            "Context id: %d", context_id);
337           proto_tree_add_item(clnp_tree, offset + sizeof(context_id),
338                            sizeof(sequence_length),
339                            "Sequence length: %d", sequence_length);
340           proto_tree_add_item(clnp_tree,
341                            offset + 
342                            sizeof(context_id) + sizeof(sequence_length),
343                            sequence_length,
344                            "Sequence data: <not shown>");
345         }
346
347         offset += sizeof(context_id) + sizeof(sequence_length) + sequence_length;
348         offset += (sequence_length %4) ? 4 - (sequence_length%4) : 0 ;
349
350       } /* for */
351
352     default :
353       break;
354
355   } /* switch message_type */
356
357   /* decode next parts according to message type */
358
359   switch(header.message_type) {
360
361     case Request:
362
363       switch(minor_version) {
364         case 1  :
365           memcpy(&request_1_1, &pd[offset], sizeof(request_1_1));
366           response_expected = request_1_1.response_expected;
367           request_id = (big_endian)? pntohl(&request_1_1.request_id) :
368             pletohl(&request_1_1.request_id);
369           if (tree) {
370             proto_tree_add_item(clnp_tree, offset, sizeof(request_id),
371                              "Request id: %d", request_id);
372             proto_tree_add_item(clnp_tree, offset + sizeof(request_id),
373                              sizeof(request_1_1.response_expected),
374                              "Response expected: %d", 
375                              response_expected);
376             proto_tree_add_item(clnp_tree, offset + sizeof(request_id) +
377                              sizeof(request_1_1.response_expected),
378                              3,
379                              "Reserved");
380           }
381           offset += sizeof(request_id) + 
382             sizeof(request_1_1.response_expected) + 3;
383           break;
384         case 0  :
385           memcpy(&request_1_0, &pd[offset], sizeof(request_1_0));
386           response_expected = request_1_0.response_expected;
387           request_id = (big_endian)? pntohl(&request_1_0.request_id) :
388             pletohl(&request_1_0.request_id);
389           if (tree) {
390             proto_tree_add_item(clnp_tree, offset, sizeof(request_id),
391                              "Request id: %d", request_id);
392             proto_tree_add_item(clnp_tree, offset + sizeof(request_id),
393                              sizeof(request_1_0.response_expected),
394                              "Response expected: %d", 
395                              response_expected);
396           }
397
398           offset += sizeof(request_id) + 
399             sizeof(request_1_0.response_expected);
400           break;
401         default :
402           break;
403       }
404
405       /* strange thing here with some ORBs/IIOP1.0 ? */
406       if ((offset - first_offset) % 4)
407         offset += 4 - (offset - first_offset)%4;
408
409       /* object_key */
410
411       sequence_length = (big_endian) ? 
412         pntohl(&pd[offset]) : pletohl(&pd[offset]);
413
414       if (tree) {
415         proto_tree_add_item(clnp_tree, offset, sizeof(sequence_length),
416                          "Object key length: %d", sequence_length);
417         proto_tree_add_item(clnp_tree, offset + sizeof(sequence_length),
418                          sequence_length,
419                          "Object key: %s",
420                          print_object_key(sequence_length, 
421                            (u_char *)&pd[offset + sizeof(sequence_length)]));
422       }
423
424       /* operation & requesting_principal */
425
426       offset += sizeof(sequence_length) + sequence_length;
427       offset += (sequence_length %4) ? 4 - (sequence_length%4) : 0 ;
428
429       sequence_length = (big_endian) ? 
430         pntohl(&pd[offset]) : pletohl(&pd[offset]);
431
432       if (sequence_length > message_size) {
433         dissect_data(pd, offset, fd, tree);
434         return;
435       }
436        
437       if (tree) {
438         proto_tree_add_item(clnp_tree, offset, sizeof(sequence_length),
439                          "Operation length: %d", sequence_length);
440         proto_tree_add_item(clnp_tree, offset + sizeof(sequence_length), 
441                          sequence_length,
442                          "Operation: %s",
443                          &pd[offset+sizeof(sequence_length)]);
444         proto_tree_add_item(clnp_tree, offset +
445                          sizeof(sequence_length)+ sequence_length,
446                          message_size - END_OF_GIOP_MESSAGE - 
447                          sizeof(sequence_length) - sequence_length,
448                          "Requesting principal: <not shown>");
449       }
450
451       if (check_col(fd, COL_INFO)) {
452         col_add_fstr(fd, COL_INFO, "Request %s %d: %s",
453                 response_expected ? "two-way" : "one-way" ,
454                 request_id,
455                 &pd[offset+sizeof(sequence_length)]);
456       }
457
458       break;
459
460     case Reply :
461
462       memcpy(&reply, &pd[offset], sizeof(reply));
463       request_id =  (big_endian) ? 
464         pntohl(&reply.request_id) : pletohl(&reply.request_id);
465       reply_status = (big_endian) ? 
466         pntohl(&reply.reply_status) : pletohl(&reply.reply_status);
467
468       if (tree) {
469         proto_tree_add_item(clnp_tree, offset, sizeof(request_id),
470                          "Request id: %d", request_id);
471         proto_tree_add_item(clnp_tree, offset + sizeof(request_id), 
472                          sizeof(reply_status),
473                          "Reply status: %s",
474                          reply_status == NO_EXCEPTION ? "no exception" :
475                          reply_status == USER_EXCEPTION ? "user exception" :
476                          reply_status == SYSTEM_EXCEPTION ? "system exception" :
477                          reply_status == LOCATION_FORWARD ? "location forward" :
478                          "?");
479       }
480
481       if (check_col(fd, COL_INFO)) {
482         col_add_fstr(fd, COL_INFO, "Reply %d: %s",
483                 request_id,
484                 reply_status == NO_EXCEPTION ? "no exception" :
485                 reply_status == USER_EXCEPTION ? "user exception" :
486                 reply_status == SYSTEM_EXCEPTION ? "system exception" :
487                 reply_status == LOCATION_FORWARD ? "location forward" :
488                 "?");
489       }
490
491       offset += sizeof(request_id) + sizeof(reply_status);
492
493       if (reply_status == SYSTEM_EXCEPTION) {
494
495         u_int minor_code_value;
496         u_int completion_status;
497
498         sequence_length = (big_endian) ? 
499           pntohl(&pd[offset]) : pletohl(&pd[offset]);
500
501         if (sequence_length > message_size) {
502           dissect_data(pd, offset, fd, tree);
503           return;
504         }
505
506         if (tree) {
507           proto_tree_add_item(clnp_tree, offset, sizeof(sequence_length),
508                            "Exception length: %d", sequence_length);
509           proto_tree_add_item(clnp_tree, offset + sizeof(sequence_length), 
510                            sequence_length,
511                            "Exception id: %s",
512                            &pd[offset+sizeof(sequence_length)]);
513
514         }
515
516         offset += sizeof(sequence_length) + sequence_length;
517
518         minor_code_value = (big_endian) ? 
519           pntohl(&pd[offset]) : pletohl(&pd[offset]);
520         completion_status = (big_endian) ? 
521           pntohl(&pd[offset+sizeof(minor_code_value)]) :
522           pletohl(&pd[offset+sizeof(minor_code_value)]);
523         
524         if (tree) {
525           proto_tree_add_item(clnp_tree, offset, sizeof(minor_code_value),
526                            "Minor code value: %d", minor_code_value);
527           proto_tree_add_item(clnp_tree, offset + sizeof(minor_code_value),
528                            sizeof(completion_status),
529                            "Completion Status: %d",
530                            completion_status);
531           
532         }
533
534       }
535       else if (reply_status == USER_EXCEPTION) {
536
537         sequence_length = (big_endian) ? 
538           pntohl(&pd[offset]) : pletohl(&pd[offset]);
539
540         if (sequence_length > message_size) {
541           dissect_data(pd, offset, fd, tree);
542           return;
543         }
544
545         if (tree) {
546           proto_tree_add_item(clnp_tree, offset, sizeof(sequence_length),
547                            "Exception length: %d", sequence_length);
548           proto_tree_add_item(clnp_tree, offset + sizeof(sequence_length), 
549                            sequence_length,
550                            "Exception id: %s",
551                            &pd[offset+sizeof(sequence_length)]);
552
553         }
554
555         offset += sizeof(sequence_length) + sequence_length;
556
557         sequence_length = (big_endian) ? 
558           pntohl(&pd[offset]) : pletohl(&pd[offset]);
559
560         if (sequence_length > message_size) {
561           dissect_data(pd, offset, fd, tree);
562           return;
563         }
564
565         if (tree && sequence_length) {
566           proto_tree_add_item(clnp_tree, offset, sizeof(sequence_length),
567                            "Exception member length: %d", sequence_length);
568           proto_tree_add_item(clnp_tree, offset + sizeof(sequence_length), 
569                            sequence_length,
570                            "Exception member: %s",
571                            &pd[offset+sizeof(sequence_length)]);
572         }
573
574         offset += sizeof(sequence_length) + sequence_length;
575
576       }
577       else {
578         
579         if (tree) {
580           proto_tree_add_item(clnp_tree, offset,
581                            message_size - END_OF_GIOP_MESSAGE,
582                            "Reply body: <not shown>");
583         }
584
585       } /* reply_status */
586
587       break;
588
589     case LocateRequest :
590
591       memcpy(&locate_req, &pd[offset], sizeof(locate_req));
592       request_id =  (big_endian) ? 
593         pntohl(&locate_req.request_id) : pletohl(&locate_req.request_id);
594
595       sequence_length = (big_endian) ? 
596         pntohl(&pd[offset+sizeof(request_id)]) : 
597         pletohl(&pd[offset+sizeof(request_id)]);
598
599       if (tree) {
600         proto_tree_add_item(clnp_tree, offset, sizeof(request_id),
601                          "Request id: %d", request_id);
602         proto_tree_add_item(clnp_tree, offset + sizeof(request_id), 
603                          sizeof(sequence_length),
604                          "Object key length: %d", sequence_length);
605         offset += sizeof(request_id) + sizeof(sequence_length);
606         proto_tree_add_item(clnp_tree,
607                          offset,
608                          sequence_length,
609                          "Object key: %s", 
610                          print_object_key(sequence_length, 
611                                           (u_char *)&pd[offset]));
612       }
613
614       if (check_col(fd, COL_INFO)) {
615         col_add_fstr(fd, COL_INFO, "LocateRequest %d", request_id);
616       }
617
618       break;
619
620     case LocateReply :
621
622       memcpy(&locate_rep, &pd[offset], sizeof(locate_rep));
623       request_id =  (big_endian) ? 
624         pntohl(&locate_rep.request_id) : pletohl(&locate_rep.request_id);
625       locate_status = (big_endian) ? 
626         pntohl(&locate_rep.locate_status) : pletohl(&locate_rep.locate_status);
627
628       if (tree) {
629         proto_tree_add_item(clnp_tree, offset, sizeof(request_id),
630                          "Request id: %d", request_id);
631         proto_tree_add_item(clnp_tree, offset + sizeof(request_id), 
632                          sizeof(locate_status),
633                          "Locate status: %d", locate_status);
634         offset += sizeof(request_id) + sizeof(locate_status);
635         if (locate_status == OBJECT_FORWARD) {
636           proto_tree_add_item(clnp_tree, offset,
637                            message_size - END_OF_GIOP_MESSAGE,
638                            "Locate reply body: <not shown>");
639         }
640       }
641
642       if (check_col(fd, COL_INFO)) {
643         col_add_fstr(fd, COL_INFO, "LocateReply %d: %s",
644                 request_id, 
645                 (locate_status == UNKNOWN_OBJECT) ? "Unknown object" :
646                 (locate_status == OBJECT_HERE) ? "Object here" :
647                 (locate_status == OBJECT_FORWARD) ? "Object forward" : "?");
648       }
649
650       break;
651
652     case CancelRequest :
653
654       request_id =  (big_endian) ? 
655         pntohl(&pd[offset]) : pletohl(&pd[offset]);
656
657       if (tree) {
658         proto_tree_add_item(clnp_tree, offset, sizeof(request_id),
659                          "Request id: %d", request_id);
660       }
661
662       if (check_col(fd, COL_INFO)) {
663         col_add_fstr(fd, COL_INFO, "CancelRequest %d", request_id);
664       }
665
666       break;
667
668     case CloseConnection :
669       if (check_col(fd, COL_INFO)) {
670         col_add_str(fd, COL_INFO, "CloseConnection");
671       }
672       break;
673
674     case MessageError :
675       if (check_col(fd, COL_INFO)) {
676         col_add_str(fd, COL_INFO, "MessageError");
677       }
678       break;
679
680     case Fragment :
681       if (check_col(fd, COL_INFO)) {
682         col_add_str(fd, COL_INFO, "Fragment");
683       }
684       break;
685
686     default :
687       break;
688
689   } /* switch message_type */
690
691
692   offset = first_offset + GIOP_HEADER_SIZE + message_size;
693
694   if (offset < fd->cap_len) {
695     dissect_data(pd, offset, fd, tree);
696   }
697
698 } /* dissect_giop */
699