Fix the bitmask for the hour field in a DOS-format time (not that 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  *
6  * $Id: packet-giop.c,v 1.1 1998/11/18 03:04:25 gerald 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 #include <gtk/gtk.h>
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <ctype.h>
39
40 #ifdef HAVE_SYS_TYPES_H
41 # include <sys/types.h>
42 #endif
43
44 #include "ethereal.h"
45 #include "packet.h"
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, GtkTree *tree) 
191 {
192
193   MessageHeader header;
194   GtkWidget *clnp_tree = NULL, *ti;
195   u_char response_expected = 0;
196   u_int first_offset = offset;
197   u_int big_endian = FALSE;
198   u_int request_id = 0;
199   u_int message_size;
200   u_int minor_version;
201   u_int context_id;
202   u_int reply_status;
203   u_int locate_status;
204   u_int sequence_length;
205   u_int nr_seq;
206   RequestHeader_1_1 request_1_1;
207   RequestHeader_1_0 request_1_0;
208   ReplyHeader reply;
209   LocateReplyHeader locate_rep;
210   LocateRequestHeader locate_req;
211   int i;
212
213 #define END_OF_GIOP_MESSAGE (offset - first_offset - GIOP_HEADER_SIZE)
214
215   if (fd->cap_len < offset + GIOP_HEADER_SIZE) {
216     dissect_data(pd, offset, fd, tree);
217     return;
218   }
219
220   /* avoid alignment problem */
221
222   memcpy(&header, &pd[offset], sizeof(header));
223
224   /* check magic number and version */
225
226   if (memcmp(header.magic, GIOP_MAGIC, sizeof(header.magic)) != 0) {
227     dissect_data(pd, offset, fd, tree);
228     return;
229   }
230
231   if (header.GIOP_version.major != GIOP_MAJOR ||
232       ((minor_version = header.GIOP_version.minor) >  GIOP_MINOR)) {
233     dissect_data(pd, offset, fd, tree);
234     return;
235   }
236
237   switch(minor_version) {
238     case 1  :
239       if (header.flags & 0x01)
240         big_endian = FALSE;
241       else
242         big_endian = TRUE;
243       break;
244     case 0  :
245       if (header.flags)
246         big_endian = FALSE;
247       else
248         big_endian = TRUE;
249       break;
250     default :
251       break;
252   }
253   
254   if (big_endian)
255     message_size = pntohl(&header.message_size);
256   else
257     message_size = pletohl(&header.message_size);
258
259   if (check_col(fd, COL_PROTOCOL)) {
260     col_add_str(fd, COL_PROTOCOL, "GIOP");
261   }
262
263   if (tree) {
264     ti = add_item_to_tree(GTK_WIDGET(tree), offset, 
265                           GIOP_HEADER_SIZE + message_size,
266                           "General Inter-ORB Protocol");
267     clnp_tree = gtk_tree_new();
268     add_subtree(ti, clnp_tree, ETT_GIOP);
269     add_item_to_tree(clnp_tree, offset,      4,
270                      "Magic number: %s", GIOP_MAGIC);
271     add_item_to_tree(clnp_tree, offset +  4, 2, 
272                      "Version: %d.%d", 
273                      header.GIOP_version.major,
274                      header.GIOP_version.minor);
275     switch(minor_version) {
276       case 1  :
277         add_item_to_tree(clnp_tree, offset +  6, 1, 
278                          "Flags: 0x%02x (%s%s)", 
279                          header.flags,
280                          (big_endian) ? "little" : "big",
281                          (header.flags & 0x02) ? " fragment" : "");
282         break;
283       case 0  :
284         add_item_to_tree(clnp_tree, offset +  6, 1, 
285                          "Byte ordering: %s endian",
286                          (big_endian) ? "little" : "big");
287         break;
288       default :
289         break;
290     } /* minor_version */
291
292     add_item_to_tree(clnp_tree, offset +  7, 1, 
293                      "Message type: %s",
294                      (header.message_type == Request) ? "Request" :
295                      (header.message_type == Reply) ? "Reply" :
296                      (header.message_type == CancelRequest) ? "CancelRequest" :
297                      (header.message_type == LocateRequest) ? "LocateRequest" :
298                      (header.message_type == LocateReply) ? "LocateReply" :
299                      (header.message_type == CloseConnection) ? "CloseConnection" :
300                      (header.message_type == MessageError) ? "MessageError" :
301                      (header.message_type == Fragment) ? "Fragment" : "?");
302
303     add_item_to_tree(clnp_tree, offset +  8, 4, 
304                      "Message size: %d", message_size);
305
306   } /* tree */
307
308   offset += GIOP_HEADER_SIZE;
309
310   if (fd->cap_len < offset + message_size) {
311     dissect_data(pd, offset, fd, tree);
312     return;
313   }
314
315   /* skip service_context in Request/Reply messages */
316
317   switch(header.message_type) {
318
319     case Request:
320     case Reply :
321
322       nr_seq = (big_endian) ? pntohl(&pd[offset]) : pletohl(&pd[offset]);
323
324       offset += sizeof(nr_seq);
325
326       for (i = 0 ; i < nr_seq ; i++) {
327
328         if (big_endian) {       
329           context_id = pntohl(&pd[offset]);
330           sequence_length = pntohl(&pd[offset + sizeof(context_id)]);
331         }
332         else {
333           context_id = pletohl(&pd[offset]);
334           sequence_length = pletohl(&pd[offset + sizeof(context_id)]);
335         }
336
337         if (tree) {
338           add_item_to_tree(clnp_tree, offset, sizeof(context_id),
339                            "Context id: %d", context_id);
340           add_item_to_tree(clnp_tree, offset + sizeof(context_id),
341                            sizeof(sequence_length),
342                            "Sequence length: %d", sequence_length);
343           add_item_to_tree(clnp_tree,
344                            offset + 
345                            sizeof(context_id) + sizeof(sequence_length),
346                            sequence_length,
347                            "Sequence data: <not shown>");
348         }
349
350         offset += sizeof(context_id) + sizeof(sequence_length) + sequence_length;
351         offset += (sequence_length %4) ? 4 - (sequence_length%4) : 0 ;
352
353       } /* for */
354
355     default :
356       break;
357
358   } /* switch message_type */
359
360   /* decode next parts according to message type */
361
362   switch(header.message_type) {
363
364     case Request:
365
366       switch(minor_version) {
367         case 1  :
368           memcpy(&request_1_1, &pd[offset], sizeof(request_1_1));
369           response_expected = request_1_1.response_expected;
370           request_id = (big_endian)? pntohl(&request_1_1.request_id) :
371             pletohl(&request_1_1.request_id);
372           if (tree) {
373             add_item_to_tree(clnp_tree, offset, sizeof(request_id),
374                              "Request id: %d", request_id);
375             add_item_to_tree(clnp_tree, offset + sizeof(request_id),
376                              sizeof(request_1_1.response_expected),
377                              "Response expected: %d", 
378                              response_expected);
379             add_item_to_tree(clnp_tree, offset + sizeof(request_id) +
380                              sizeof(request_1_1.response_expected),
381                              3,
382                              "Reserved");
383           }
384           offset += sizeof(request_id) + 
385             sizeof(request_1_1.response_expected) + 3;
386           break;
387         case 0  :
388           memcpy(&request_1_0, &pd[offset], sizeof(request_1_0));
389           response_expected = request_1_0.response_expected;
390           request_id = (big_endian)? pntohl(&request_1_0.request_id) :
391             pletohl(&request_1_0.request_id);
392           if (tree) {
393             add_item_to_tree(clnp_tree, offset, sizeof(request_id),
394                              "Request id: %d", request_id);
395             add_item_to_tree(clnp_tree, offset + sizeof(request_id),
396                              sizeof(request_1_0.response_expected),
397                              "Response expected: %d", 
398                              response_expected);
399           }
400
401           offset += sizeof(request_id) + 
402             sizeof(request_1_0.response_expected);
403           break;
404         default :
405           break;
406       }
407
408       /* strange thing here with some ORBs/IIOP1.0 ? */
409       if ((offset - first_offset) % 4)
410         offset += 4 - (offset - first_offset)%4;
411
412       /* object_key */
413
414       sequence_length = (big_endian) ? 
415         pntohl(&pd[offset]) : pletohl(&pd[offset]);
416
417       if (tree) {
418         add_item_to_tree(clnp_tree, offset, sizeof(sequence_length),
419                          "Object key length: %d", sequence_length);
420         add_item_to_tree(clnp_tree, offset + sizeof(sequence_length),
421                          sequence_length,
422                          "Object key: %s",
423                          print_object_key(sequence_length, 
424                            (u_char *)&pd[offset + sizeof(sequence_length)]));
425       }
426
427       /* operation & requesting_principal */
428
429       offset += sizeof(sequence_length) + sequence_length;
430       offset += (sequence_length %4) ? 4 - (sequence_length%4) : 0 ;
431
432       sequence_length = (big_endian) ? 
433         pntohl(&pd[offset]) : pletohl(&pd[offset]);
434
435       if (sequence_length > message_size) {
436         dissect_data(pd, offset, fd, tree);
437         return;
438       }
439        
440       if (tree) {
441         add_item_to_tree(clnp_tree, offset, sizeof(sequence_length),
442                          "Operation length: %d", sequence_length);
443         add_item_to_tree(clnp_tree, offset + sizeof(sequence_length), 
444                          sequence_length,
445                          "Operation: %s",
446                          &pd[offset+sizeof(sequence_length)]);
447         add_item_to_tree(clnp_tree, offset +
448                          sizeof(sequence_length)+ sequence_length,
449                          message_size - END_OF_GIOP_MESSAGE - 
450                          sizeof(sequence_length) - sequence_length,
451                          "Requesting principal: <not shown>");
452       }
453
454       if (check_col(fd, COL_INFO)) {
455         col_add_fstr(fd, COL_INFO, "Request %s %d: %s",
456                 response_expected ? "two-way" : "one-way" ,
457                 request_id,
458                 &pd[offset+sizeof(sequence_length)]);
459       }
460
461       break;
462
463     case Reply :
464
465       memcpy(&reply, &pd[offset], sizeof(reply));
466       request_id =  (big_endian) ? 
467         pntohl(&reply.request_id) : pletohl(&reply.request_id);
468       reply_status = (big_endian) ? 
469         pntohl(&reply.reply_status) : pletohl(&reply.reply_status);
470
471       if (tree) {
472         add_item_to_tree(clnp_tree, offset, sizeof(request_id),
473                          "Request id: %d", request_id);
474         add_item_to_tree(clnp_tree, offset + sizeof(request_id), 
475                          sizeof(reply_status),
476                          "Reply status: %s",
477                          reply_status == NO_EXCEPTION ? "no exception" :
478                          reply_status == USER_EXCEPTION ? "user exception" :
479                          reply_status == SYSTEM_EXCEPTION ? "system exception" :
480                          reply_status == LOCATION_FORWARD ? "location forward" :
481                          "?");
482       }
483
484       if (check_col(fd, COL_INFO)) {
485         col_add_fstr(fd, COL_INFO, "Reply %d: %s",
486                 request_id,
487                 reply_status == NO_EXCEPTION ? "no exception" :
488                 reply_status == USER_EXCEPTION ? "user exception" :
489                 reply_status == SYSTEM_EXCEPTION ? "system exception" :
490                 reply_status == LOCATION_FORWARD ? "location forward" :
491                 "?");
492       }
493
494       offset += sizeof(request_id) + sizeof(reply_status);
495
496       if (reply_status == SYSTEM_EXCEPTION) {
497
498         u_int minor_code_value;
499         u_int completion_status;
500
501         sequence_length = (big_endian) ? 
502           pntohl(&pd[offset]) : pletohl(&pd[offset]);
503
504         if (sequence_length > message_size) {
505           dissect_data(pd, offset, fd, tree);
506           return;
507         }
508
509         if (tree) {
510           add_item_to_tree(clnp_tree, offset, sizeof(sequence_length),
511                            "Exception length: %d", sequence_length);
512           add_item_to_tree(clnp_tree, offset + sizeof(sequence_length), 
513                            sequence_length,
514                            "Exception id: %s",
515                            &pd[offset+sizeof(sequence_length)]);
516
517         }
518
519         offset += sizeof(sequence_length) + sequence_length;
520
521         minor_code_value = (big_endian) ? 
522           pntohl(&pd[offset]) : pletohl(&pd[offset]);
523         completion_status = (big_endian) ? 
524           pntohl(&pd[offset+sizeof(minor_code_value)]) :
525           pletohl(&pd[offset+sizeof(minor_code_value)]);
526         
527         if (tree) {
528           add_item_to_tree(clnp_tree, offset, sizeof(minor_code_value),
529                            "Minor code value: %d", minor_code_value);
530           add_item_to_tree(clnp_tree, offset + sizeof(minor_code_value),
531                            sizeof(completion_status),
532                            "Completion Status: %d",
533                            completion_status);
534           
535         }
536
537       }
538       else if (reply_status == USER_EXCEPTION) {
539
540         sequence_length = (big_endian) ? 
541           pntohl(&pd[offset]) : pletohl(&pd[offset]);
542
543         if (sequence_length > message_size) {
544           dissect_data(pd, offset, fd, tree);
545           return;
546         }
547
548         if (tree) {
549           add_item_to_tree(clnp_tree, offset, sizeof(sequence_length),
550                            "Exception length: %d", sequence_length);
551           add_item_to_tree(clnp_tree, offset + sizeof(sequence_length), 
552                            sequence_length,
553                            "Exception id: %s",
554                            &pd[offset+sizeof(sequence_length)]);
555
556         }
557
558         offset += sizeof(sequence_length) + sequence_length;
559
560         sequence_length = (big_endian) ? 
561           pntohl(&pd[offset]) : pletohl(&pd[offset]);
562
563         if (sequence_length > message_size) {
564           dissect_data(pd, offset, fd, tree);
565           return;
566         }
567
568         if (tree && sequence_length) {
569           add_item_to_tree(clnp_tree, offset, sizeof(sequence_length),
570                            "Exception member length: %d", sequence_length);
571           add_item_to_tree(clnp_tree, offset + sizeof(sequence_length), 
572                            sequence_length,
573                            "Exception member: %s",
574                            &pd[offset+sizeof(sequence_length)]);
575         }
576
577         offset += sizeof(sequence_length) + sequence_length;
578
579       }
580       else {
581         
582         if (tree) {
583           add_item_to_tree(clnp_tree, offset,
584                            message_size - END_OF_GIOP_MESSAGE,
585                            "Reply body: <not shown>");
586         }
587
588       } /* reply_status */
589
590       break;
591
592     case LocateRequest :
593
594       memcpy(&locate_req, &pd[offset], sizeof(locate_req));
595       request_id =  (big_endian) ? 
596         pntohl(&locate_req.request_id) : pletohl(&locate_req.request_id);
597
598       sequence_length = (big_endian) ? 
599         pntohl(&pd[offset+sizeof(request_id)]) : 
600         pletohl(&pd[offset+sizeof(request_id)]);
601
602       if (tree) {
603         add_item_to_tree(clnp_tree, offset, sizeof(request_id),
604                          "Request id: %d", request_id);
605         add_item_to_tree(clnp_tree, offset + sizeof(request_id), 
606                          sizeof(sequence_length),
607                          "Object key length: %d", sequence_length);
608         offset += sizeof(request_id) + sizeof(sequence_length);
609         add_item_to_tree(clnp_tree,
610                          offset,
611                          sequence_length,
612                          "Object key: %s", 
613                          print_object_key(sequence_length, 
614                                           (u_char *)&pd[offset]));
615       }
616
617       if (check_col(fd, COL_INFO)) {
618         col_add_fstr(fd, COL_INFO, "LocateRequest %d", request_id);
619       }
620
621       break;
622
623     case LocateReply :
624
625       memcpy(&locate_rep, &pd[offset], sizeof(locate_rep));
626       request_id =  (big_endian) ? 
627         pntohl(&locate_rep.request_id) : pletohl(&locate_rep.request_id);
628       locate_status = (big_endian) ? 
629         pntohl(&locate_rep.locate_status) : pletohl(&locate_rep.locate_status);
630
631       if (tree) {
632         add_item_to_tree(clnp_tree, offset, sizeof(request_id),
633                          "Request id: %d", request_id);
634         add_item_to_tree(clnp_tree, offset + sizeof(request_id), 
635                          sizeof(locate_status),
636                          "Locate status: %d", locate_status);
637         offset += sizeof(request_id) + sizeof(locate_status);
638         if (locate_status == OBJECT_FORWARD) {
639           add_item_to_tree(clnp_tree, offset,
640                            message_size - END_OF_GIOP_MESSAGE,
641                            "Locate reply body: <not shown>");
642         }
643       }
644
645       if (check_col(fd, COL_INFO)) {
646         col_add_fstr(fd, COL_INFO, "LocateReply %d: %s",
647                 request_id, 
648                 (locate_status == UNKNOWN_OBJECT) ? "Unknown object" :
649                 (locate_status == OBJECT_HERE) ? "Object here" :
650                 (locate_status == OBJECT_FORWARD) ? "Object forward" : "?");
651       }
652
653       break;
654
655     case CancelRequest :
656
657       request_id =  (big_endian) ? 
658         pntohl(&pd[offset]) : pletohl(&pd[offset]);
659
660       if (tree) {
661         add_item_to_tree(clnp_tree, offset, sizeof(request_id),
662                          "Request id: %d", request_id);
663       }
664
665       if (check_col(fd, COL_INFO)) {
666         col_add_fstr(fd, COL_INFO, "CancelRequest %d", request_id);
667       }
668
669       break;
670
671     case CloseConnection :
672       if (check_col(fd, COL_INFO)) {
673         col_add_str(fd, COL_INFO, "CloseConnection");
674       }
675       break;
676
677     case MessageError :
678       if (check_col(fd, COL_INFO)) {
679         col_add_str(fd, COL_INFO, "MessageError");
680       }
681       break;
682
683     case Fragment :
684       if (check_col(fd, COL_INFO)) {
685         col_add_str(fd, COL_INFO, "Fragment");
686       }
687       break;
688
689     default :
690       break;
691
692   } /* switch message_type */
693
694
695   offset = first_offset + GIOP_HEADER_SIZE + message_size;
696
697   if (offset < fd->cap_len) {
698     dissect_data(pd, offset, fd, tree);
699   }
700
701 } /* dissect_giop */
702