Added two new arguments to epan_init() and proto_init() to
[obnox/wireshark/wip.git] / packet-smb-pipe.c
1 /* packet-smb-pipe.c
2  * Routines for SMB named pipe packet dissection
3  * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
4  *
5  * $Id: packet-smb-pipe.c,v 1.21 2001/03/22 00:50:44 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-pop.c
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 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
36 #endif
37
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif
41
42 #include <time.h>
43 #include <string.h>
44 #include <glib.h>
45 #include <ctype.h>
46 #include "packet.h"
47 #include "conversation.h"
48 #include "smb.h"
49 #include "alignment.h"
50 #include "strutil.h"
51 #include "packet-smb-pipe.h"
52
53 static int proto_smb_lanman = -1;
54
55 static gint ett_lanman = -1;
56 static gint ett_lanman_servers = -1;
57 static gint ett_lanman_server = -1;
58 static gint ett_lanman_shares = -1;
59 static gint ett_lanman_share = -1;
60 static gint ett_lanman_flags = -1;
61
62 /*
63  * See
64  *
65  *      ftp://ftp.microsoft.com/developr/drg/CIFS/cifsrap2.txt
66  *
67  * among other documents.
68  */
69
70 /* 
71  * The following data structure describes the LANMAN requests we understand
72  *
73  * Simply fill in the number, name, and parameter names if you know them
74  * Try to keep them in order 
75  *
76  * We will extend this data structure as we try to decode more ...
77  */
78
79 struct lanman_desc {
80   int   lanman_num;
81   char  *lanman_name;
82   char  **req;
83   char  **req_data;     /* Hmmm, not flexible enough */
84   char  **resp;
85   char  **resp_data;
86 };
87
88 static char *lm_params_req_0[]   = {"Detail Level", "Return Buffer Size", NULL};
89 static char *lm_params_req_1[]   = {"Share Name", "Detail Level", "Receive Buffer Size", NULL};
90 static char *lm_params_resp_1[]  = {"Returned Data Len", NULL};
91 static char *lm_params_req_13[]  = {"Detail Level", "Receive Buffer Size", NULL};
92 static char *lm_params_req_56[]  = {"User Name", "Detail Level", "Receive Buffer Size", NULL};
93 static char *lm_params_req_104[] = {"Detail Level", "Return Buffer Size", "Server Type", "Domain", NULL};
94 static char *lm_params_req_132[] = {"Reserved1", "Reserved2", "Detail Level", "UserInfoStruct?", "Length of UStruct", "Receive Buffer Size", NULL};
95 static char *lm_params_req_133[] = {"Reserved1", "Reserved2", "Detail Level", "UserInfoStruct?", "Length of UStruct", "Receive Buffer Size", NULL};
96
97 static char *lm_null_params[] = {NULL};
98
99 struct lanman_desc lmd[] = {
100   {0, "NetShareEnum", lm_params_req_0, lm_null_params, lm_null_params, lm_null_params},
101   {1, "NetShareGetInfo", lm_params_req_1, lm_null_params, lm_params_resp_1, lm_null_params},
102   {13, "NetServerGetInfo", lm_params_req_13, lm_null_params, lm_null_params, lm_null_params},
103   {52, "NetGroupGetUsers", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
104   {56, "NetUserGetInfo", lm_params_req_56, lm_null_params, lm_null_params, lm_null_params},
105   {59, "NetUserGetGroups", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
106   {63, "NetWkstaGetInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
107   {69, "DOSPrintQEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
108   {70, "DOSPrintQGetInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
109   {74, "WPrintQueuePause", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
110   {75, "WPrintQueueResume", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
111   {76, "WPrintJobEnumerate", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
112   {77, "WPrintJobGetInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
113   {81, "RDOSPrintJobDel", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
114   {82, "RDOSPrintJobPause", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
115   {83, "RDOSPrintJobResume", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
116   {84, "WPrintDestEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
117   {85, "WPrintDestGetInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
118   {91, "NetRemoteTOD", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
119   {103, "WPrintQueuePurge", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
120   {104, "NetServerEnum2", lm_params_req_104, lm_null_params, lm_null_params, lm_null_params},
121   {105, "WAccessGetUserPerms", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
122   {115, "SetUserPassword", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
123   {132, "NetWkstaUserLogon", lm_params_req_132, lm_null_params, lm_null_params, lm_null_params},
124   {133, "NetWkstaUserLogoff", lm_params_req_133, lm_null_params, lm_null_params, lm_null_params},
125   {147, "PrintJobInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
126   {205, "WPrintDriverEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
127   {206, "WPrintQProcEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
128   {207, "WPrintPortEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
129   {214, "SamOEMChangePassword", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
130   {-1, NULL, NULL,NULL, NULL, NULL}
131 };
132
133 static struct lanman_desc *
134 find_lanman(int lanman_num)
135 {
136   int i = 0;
137
138   /* FIXME, This could be more efficient */
139
140   while (lmd[i].lanman_num != -1) {
141
142     if (lmd[i].lanman_num == lanman_num) {
143
144       return &lmd[i];
145
146     }
147
148     i++;
149
150   }
151
152   return NULL;
153
154 }
155
156
157 #define NETSHAREENUM   0x00  /* 00  */
158 #define NETSERVERENUM2 0x68  /* 104 */
159
160 static void
161 dissect_server_flags(proto_tree *tree, int offset, int length, int flags)
162 {
163   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
164                       decode_boolean_bitfield(flags, 0x0001, length*8, "Workstation", "Not Workstation"));
165   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
166                       decode_boolean_bitfield(flags, 0x0002, length*8, "Server", "Not Server"));
167   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
168                       decode_boolean_bitfield(flags, 0x0004, length*8, "SQL Server", "Not SQL Server"));
169   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
170                       decode_boolean_bitfield(flags, 0x0008, length*8, "Domain Controller", "Not Domain Controller"));
171   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
172                       decode_boolean_bitfield(flags, 0x0010, length*8, "Backup Controller", "Not Backup Controller"));
173   proto_tree_add_text(tree, NullTVB, offset, 4, "%s",
174                       decode_boolean_bitfield(flags, 0x0020, length*8, "Time Source", "Not Time Source"));
175   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
176                       decode_boolean_bitfield(flags, 0x0040, length*8, "Apple Server", "Not Apple Server"));
177   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
178                       decode_boolean_bitfield(flags, 0x0080, length*8, "Novell Server", "Not Novell Server"));
179   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
180                       decode_boolean_bitfield(flags, 0x0100, length*8, "Domain Member Server", "Not Domain Member Server"));
181   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
182                       decode_boolean_bitfield(flags, 0x0200, length*8, "Print Queue Server", "Not Print Queue Server"));      
183   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
184                       decode_boolean_bitfield(flags, 0x0400, length*8, "Dialin Server", "Not Dialin Server"));
185   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
186                       decode_boolean_bitfield(flags, 0x0800, length*8, "Xenix Server", "Not Xenix Server"));
187   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
188                       decode_boolean_bitfield(flags, 0x1000, length*8, "NT Workstation", "Not NT Workstation"));
189   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
190                       decode_boolean_bitfield(flags, 0x2000, length*8, "Windows for Workgroups", "Not Windows for Workgroups"));
191   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
192                       decode_boolean_bitfield(flags, 0x8000, length*8, "NT Server", "Not NT Server"));
193   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
194                       decode_boolean_bitfield(flags, 0x10000, length*8, "Potential Browser", "Not Potential Browser"));
195   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
196                       decode_boolean_bitfield(flags, 0x20000, length*8, "Backup Browser", "Not Backup Browser"));
197   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
198                       decode_boolean_bitfield(flags, 0x40000, length*8, "Master Browser", "Not Master Browser"));
199   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
200                       decode_boolean_bitfield(flags, 0x80000, length*8, "Domain Master Browser", "Not Domain Master Browser"));
201   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
202                       decode_boolean_bitfield(flags, 0x100000, length*8, "OSF", "Not OSF"));
203   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
204                       decode_boolean_bitfield(flags, 0x200000, length*8, "VMS", "Not VMS"));
205   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
206                       decode_boolean_bitfield(flags, 0x400000, length*8, "Windows 95 or above", "Not Windows 95 or above"));
207   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
208                       decode_boolean_bitfield(flags, 0x40000000, length*8, "Local List Only", "Not Local List Only"));
209   proto_tree_add_text(tree, NullTVB, offset, length, "%s",
210                       decode_boolean_bitfield(flags, 0x80000000, length*8, "Domain Enum", "Not Domain Enum"));
211
212 }
213
214
215
216 static char *p_desc = NULL, *d_desc = NULL, *data = NULL, *params = NULL;
217 static int p_count, d_count, p_offset, d_offset, d_current = 0, p_current = 0;
218 static int pd_p_current = 0, pd_d_current = 0, in_params = 0, need_data = 0;
219 static int lm_ent_count = 0, lm_act_count = 0; 
220
221 /* Initialize the various data structure */
222 static void 
223 dissect_transact_engine_init(const u_char *pd, const char *param_desc,
224     const char *data_desc, int SMB_offset, int ParameterOffset,
225     int ParameterCount, int DataOffset, int DataCount)
226 {
227
228   d_count = DataCount;
229   p_count = ParameterCount;
230   d_offset = 0;
231   p_offset = 0;
232   d_current = 0;
233   p_current = 0;
234   lm_ent_count = lm_act_count = 0;
235   pd_d_current = DataOffset;
236   pd_p_current = ParameterOffset;
237   in_params = need_data = 0;
238
239   if (p_desc) g_free(p_desc);
240   p_desc = g_malloc(strlen(param_desc) + 1);
241   strcpy(p_desc, param_desc);
242
243   if (d_desc) g_free(d_desc);
244   d_desc= g_malloc(strlen(data_desc) + 1);
245   strcpy(d_desc, data_desc);
246
247   if (params) g_free(params);
248   params = g_malloc(p_count);
249   memcpy(params, pd + ParameterOffset, ParameterCount);
250
251   if (data) g_free(data);
252   data = g_malloc(d_count);
253   memcpy(data, pd + DataOffset, DataCount);
254
255 }
256
257 int get_ent_count()
258 {
259
260   return lm_ent_count;
261
262 }
263
264 int get_act_count()
265 {
266
267   return lm_act_count;
268
269 }
270
271 static int get_byte_count(const u_char *p_data)
272
273 {
274   int count = 0, off = 0;
275
276   while (p_data[off] && isdigit(p_data[off])) {
277
278     count = (count * 10) + (int)p_data[off++] - (int)'0';
279
280   }
281
282   return count;
283 }
284
285
286 /* Dissect the next item, if Name is null, call it by its data type  */
287 /* We pull out the next item in the appropriate place and display it */
288 /* We display the parameters first, then the data, then any auxilliary data */
289
290 static int
291 dissect_transact_next(const u_char *pd, char *Name, int dirn, proto_tree *tree)
292 {
293   /*  guint8        BParam; */
294   guint16       WParam = 0;
295   guint32       LParam = 0;
296   const char    /**Bytes,*/ *AsciiZ = NULL;
297   int           bc;
298
299   while (1) {
300
301     if (p_desc[p_offset] == 0) return 0;  /* No more ... */
302
303     switch (in_params) {
304
305     case 0:   /* We are in the params area ... */
306
307       switch (p_desc[p_offset++]) {
308
309       case 'r':
310
311         if (dirn == 0) { /* We need to process the data ... */
312           
313           need_data = 1;
314
315         }
316
317         break;
318
319       case 'h':  /* A WORD parameter received */
320
321         if (dirn == 0) {
322
323           WParam = GSHORT(pd, pd_p_current);
324
325           proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u (%04X)", (Name) ? Name : "Returned Word", WParam, WParam);
326
327           pd_p_current += 2;
328
329           lm_act_count = WParam;
330
331           return 1;
332
333         }
334
335         break;
336
337       case 'e':  /* An ent count ..  */
338
339         if (dirn == 0) { /* Only relevant in a response */
340
341           WParam = GSHORT(pd, pd_p_current);
342
343           proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: (%04X)", (Name) ? Name : "Entry Count", WParam);
344
345           pd_p_current += 2;
346
347           lm_ent_count = WParam;  /* Save this for later retrieval */
348
349           return 1;
350
351         }
352
353         break;
354
355       case 'W':  /* Word Parameter */
356
357         if (dirn == 1) {  /* A request ... */
358         
359           /* Insert a word param */
360
361           WParam = GSHORT(pd, pd_p_current);
362
363           proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u (%04X)", (Name) ? Name : "Word Param", WParam, WParam);
364
365           pd_p_current += 2;
366
367           return 1;  /* That's it here ... we have dissected a param */
368
369         }
370
371         break;
372
373       case 'i':  /* A long word is returned */
374
375         if (dirn == 0) {
376
377           LParam = GWORD(pd, pd_p_current);
378
379           proto_tree_add_text(tree, NullTVB, pd_p_current, 4, "%s: %u (0x%08X)", (Name) ? Name : "Returned Long Word", LParam, LParam);
380
381           pd_p_current += 2;
382
383           return 1;
384
385         }
386
387         break;
388
389       case 'D':  /* Double Word parameter */
390
391         if (dirn == 1) {
392
393           LParam = GWORD(pd, pd_p_current);
394
395           proto_tree_add_text(tree, NullTVB, pd_p_current, 4, "%s: %u (0x%08X)", (Name) ? Name : "DWord Param", LParam, LParam);
396
397           pd_p_current += 4;
398           
399           return 1;  /* That's it here */
400
401         }
402
403         break;
404
405       case 'g':  /* A byte or series of bytes is returned */
406
407         if (dirn == 0) {
408  
409           bc = get_byte_count(p_desc + p_offset);
410
411           proto_tree_add_text(tree, NullTVB, pd_p_current, bc, "%s%u: %s", (Name) ? Name : "B", (bc) ? bc : 1, format_text( pd + pd_p_current, (bc) ? bc : 1));
412
413           pd_p_current += (bc) ? bc : 1;
414
415           return 1;
416
417         }
418
419         break;
420
421       case 'b':  /* A byte or series of bytes */
422
423         if (dirn == 1) {
424
425           bc = get_byte_count(p_desc + p_offset);  /* This is not clean */
426
427           /*Bytes = g_malloc(bc + 1); / * Is this needed ? */
428
429           proto_tree_add_text(tree, NullTVB, pd_p_current, bc, "%s%u: %s", (Name) ? Name : "B", (bc) ? bc : 1, format_text(pd + pd_p_current, (bc) ? bc : 1));
430
431           pd_p_current += (bc) ? bc : 1;
432
433           return 1;  /* That's it here ... */
434
435         }
436
437         break;
438
439       case 'O': /* A null pointer */
440
441         if (dirn == 1) {
442
443           proto_tree_add_text(tree, NullTVB, pd_p_current, 0, "%s: Null Pointer", (Name) ? Name : "Unknown");
444
445           return 1;  /* That's it here */
446
447         }
448
449         break;
450
451       case 'z': /* An AsciiZ string */
452
453         if (dirn == 1) {
454
455           AsciiZ = pd + pd_p_current;
456
457           proto_tree_add_text(tree, NullTVB, pd_p_current, strlen(AsciiZ) + 1, "%s: %s", (Name) ? Name : "AsciiZ", AsciiZ);
458
459           pd_p_current += strlen(AsciiZ) + 1;
460
461           return 1;  /* That's it here ... */
462
463         }
464
465         break;
466
467       case 'F': /* One or more pad bytes */
468
469         if (dirn == 1) {
470
471           bc = get_byte_count(pd);
472
473           proto_tree_add_text(tree, NullTVB, pd_p_current, bc, "%s%u: %s", (Name) ? Name : "Pad", bc, format_text(pd + pd_p_current, bc));
474
475           pd_p_current += bc;
476
477           return 1;  /* That's it here */
478
479         }
480
481         break;
482
483       case 'L': /* Receive buffer len: Short */
484
485         if (dirn == 1) {
486
487           WParam = GSHORT(pd, pd_p_current);
488
489           proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u (0x%04X)", (Name) ? Name : "Receive Buffer Len", WParam, WParam);
490
491           pd_p_current += 2;
492
493           return 1;  /* That's it here ... */
494
495         }
496
497         break;
498
499       case 's': /* Send buf ... */
500
501         if (dirn == 1) {
502
503           need_data = 1;
504
505           LParam = GWORD(pd, pd_p_current);
506
507           proto_tree_add_text(tree, NullTVB, pd_p_current, 4, "%s: %u", (Name) ? Name : "Send Buffer Ptr", LParam);
508
509           pd_p_current += 4;
510
511           return 1;  /* That's it here ... */
512
513         }
514
515         break;
516
517       case 'T':
518
519         if (dirn == 1) {
520
521           WParam = GSHORT(pd, pd_p_current);
522
523           proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u", (Name) ? Name : "Send Buffer Len", WParam);
524
525           pd_p_current += 2;
526
527           return 1;
528
529         }
530
531         break;
532         
533       default:
534
535         break;
536
537       }
538
539       break;
540
541     case 1:   /* We are in the data area ... */
542
543       
544       break;
545         
546     }
547   }
548
549   return 0;
550
551 }
552
553 static const value_string share_type_vals[] = {
554         {0, "Directory tree"},
555         {1, "Printer queue"},
556         {2, "Communications device"},
557         {3, "IPC"},
558         {0, NULL}
559 };
560
561 /*
562  * Per-frame data needed to dissect replies.
563  */
564 typedef struct {
565   guint16 FunctionCode;
566   gboolean is_continuation;
567 } response_data;
568
569 static GMemChunk  *lanman_proto_data;
570
571 gboolean
572 dissect_pipe_lanman(const u_char *pd, int offset, frame_data *fd,
573         proto_tree *parent, proto_tree *tree, struct smb_info si,
574         int max_data, int SMB_offset, int errcode, int dirn,
575         const u_char *command, int DataOffset, int DataCount,
576         int ParameterOffset, int ParameterCount)
577 {
578   gboolean            is_interim_response;
579   guint32             loc_offset;
580   guint16             FunctionCode;
581   guint16             Level;
582   guint16             RecvBufLen;
583   guint32             Flags;
584   const char          *ParameterDescriptor;
585   const char          *ReturnDescriptor;
586   proto_tree          *lanman_tree = NULL, *flags_tree = NULL;
587   proto_item          *ti;
588   struct lanman_desc  *lanman;
589   guint32             string_offset;
590
591   if (DataOffset < 0) {
592
593     /* Interim response; we weren't given any data. */
594
595     is_interim_response = TRUE;
596     loc_offset = SMB_offset;
597
598   }
599   else {
600
601     /* Offset of the data we should dissect. */
602
603     is_interim_response = FALSE;
604     loc_offset = SMB_offset + ParameterOffset;
605
606   }
607
608   if (check_col(fd, COL_PROTOCOL))
609     col_set_str(fd, COL_PROTOCOL, "LANMAN");
610
611   if (dirn == 1) { /* The request side */
612
613     FunctionCode = GSHORT(pd, loc_offset);
614
615     si.request_val -> last_lanman_cmd = FunctionCode;
616
617     lanman = find_lanman(FunctionCode);
618
619     if (check_col(fd, COL_INFO)) {
620
621       if (lanman) { 
622         col_add_fstr(fd, COL_INFO, "%s Request", lanman -> lanman_name);
623       }
624       else {
625         col_add_fstr(fd, COL_INFO, "Unknown LANMAN Request: %u", FunctionCode);
626       }
627     }
628
629     if (tree) {
630
631       ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, loc_offset, ParameterCount, FALSE);
632       lanman_tree = proto_item_add_subtree(ti, ett_lanman);
633
634       if (lanman) {
635         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Function Code: %s", lanman -> lanman_name);
636       }
637       else {
638         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Function Code: Unknown LANMAN Request: %u", FunctionCode);
639       }
640
641     }
642
643     loc_offset += 2;
644
645     ParameterDescriptor = pd + loc_offset;
646
647     /* Now, save these for later */
648
649     si.request_val -> trans_response_seen = 0; 
650
651     if (si.request_val -> last_param_descrip)
652       g_free(si.request_val -> last_param_descrip);
653     si.request_val -> last_param_descrip = g_malloc(strlen(ParameterDescriptor) + 1);
654     if (si.request_val -> last_param_descrip)
655       strcpy(si.request_val -> last_param_descrip, ParameterDescriptor);
656
657     if (tree) {
658
659       proto_tree_add_text(lanman_tree, NullTVB, loc_offset, strlen(ParameterDescriptor) + 1, "Parameter Descriptor: %s", ParameterDescriptor);
660
661     }
662
663     loc_offset += strlen(ParameterDescriptor) + 1;
664
665     ReturnDescriptor = pd + loc_offset;
666
667     if (si.request_val -> last_data_descrip)
668       g_free(si.request_val -> last_data_descrip);
669     si.request_val -> last_data_descrip = g_malloc(strlen(ReturnDescriptor) + 1);
670     if (si.request_val -> last_data_descrip)
671       strcpy(si.request_val -> last_data_descrip, ReturnDescriptor);
672
673     if (tree) {
674
675       proto_tree_add_text(lanman_tree, NullTVB, loc_offset, strlen(ReturnDescriptor) + 1, "Return Descriptor: %s", ReturnDescriptor);
676
677     }
678
679     loc_offset += strlen(ReturnDescriptor) + 1;
680
681     switch (FunctionCode) {
682
683     case NETSHAREENUM:   /* Never decode this at the moment ... */
684
685       Level = GSHORT(pd, loc_offset);
686       
687       if (tree) {
688
689         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Detail Level: %u", Level);
690
691       }
692
693       loc_offset += 2;
694
695       RecvBufLen = GSHORT(pd, loc_offset);
696       
697       if (tree) {
698
699         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Receive Buffer Length: %u", RecvBufLen);
700
701       }
702
703       loc_offset += 2;
704       
705       break;
706
707     case NETSERVERENUM2:  /* Process a NetServerEnum2 */
708
709       Level = GSHORT(pd, loc_offset);
710       si.request_val -> last_level = Level;
711
712       if (tree) {
713
714         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Info Detail Level: %u", Level);
715
716       }
717
718       loc_offset += 2;
719       
720       RecvBufLen = GSHORT(pd, loc_offset);
721       
722       if (tree) {
723
724         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Receive Buffer Length: %u", RecvBufLen);
725
726       }
727
728       loc_offset += 2;
729
730       Flags = GWORD(pd, loc_offset);
731
732       if (tree) {
733
734         ti = proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 4, "Server Types Required: 0x%08X", Flags);
735         flags_tree = proto_item_add_subtree(ti, ett_lanman_flags);
736         dissect_server_flags(flags_tree, loc_offset, 4, Flags);
737
738       }
739
740       loc_offset += 4;
741
742       return TRUE;
743       break;
744
745     default:   /* Just try to handle what is there ... */
746
747       if (tree) {
748
749         int i = 0;  /* Counter for names below */
750         char *name = NULL;
751
752         dissect_transact_engine_init(pd, ParameterDescriptor, ReturnDescriptor,SMB_offset, loc_offset, ParameterCount, DataOffset, DataCount);
753
754         if (lanman) name = lanman -> req[i];  /* Must be OK ... */
755
756         while (dissect_transact_next(pd, name, dirn, lanman_tree))
757           if (name) name = lanman -> req[++i];
758       }
759
760       break;
761     
762     }
763   }
764   else {  /* dirn == 0, response */
765     response_data    *proto_data;
766     guint16          Status;
767     guint16          Convert;
768     guint16          EntCount;
769     guint16          AvailCount;
770     int              i;
771     proto_tree       *server_tree = NULL, *flags_tree = NULL, *share_tree = NULL;
772
773     /* Is there any per-frame LANMAN data for this frame? */
774     proto_data = p_get_proto_data(fd, proto_smb_lanman);
775     if (proto_data == NULL) {
776       /* No.  Allocate some, and set it up. */
777       proto_data = g_mem_chunk_alloc(lanman_proto_data);
778       proto_data->FunctionCode = si.request_val -> last_lanman_cmd;
779
780       /*
781        * If we've already seen a response to the request, this must
782        * be a continuation of that response.
783        */
784       proto_data->is_continuation = si.request_val -> trans_response_seen;
785
786       /*
787        * Attach it to the frame.
788        */
789       p_add_proto_data(fd, proto_smb_lanman, proto_data);
790     }
791
792     FunctionCode = proto_data->FunctionCode;
793
794     /*
795      * If we have already seen the response to this transact, simply
796      * record it as a continuation ...
797      */
798     if (proto_data->is_continuation) {
799
800       if (check_col(fd, COL_INFO)) {
801           col_set_str(fd, COL_INFO, "Transact Continuation");
802       }
803       
804       if (tree) {
805
806         ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, loc_offset, END_OF_FRAME, FALSE);
807
808         lanman_tree = proto_item_add_subtree(ti, ett_lanman);
809
810         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, END_OF_FRAME, "Payload: %s", format_text(pd + loc_offset, END_OF_FRAME));
811
812       }
813
814       return TRUE;
815
816     } 
817
818     si.request_val -> trans_response_seen = 1; 
819
820     lanman = find_lanman(FunctionCode);
821
822     if (check_col(fd, COL_INFO)) {
823
824       if (lanman) {
825         col_add_fstr(fd, COL_INFO, "%s %sResponse", lanman -> lanman_name,
826                 is_interim_response ? "Interim " : "");
827       }
828       else {
829         col_add_fstr(fd, COL_INFO, "Unknown LANMAN %sResponse: %u",
830                 is_interim_response ? "Interim " : "", FunctionCode);
831       }
832     }
833
834     if (tree) {
835
836       ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, loc_offset, END_OF_FRAME, FALSE);
837       lanman_tree = proto_item_add_subtree(ti, ett_lanman);
838       if (lanman) {
839         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 0, "Function Code: %s", lanman -> lanman_name);
840       }
841       else {
842         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 0, "Function Code: Unknown LANMAN Response: %u", FunctionCode);
843       }
844     }
845
846     if (is_interim_response) {
847
848       return TRUE;      /* no data to dissect */
849
850     }
851
852     switch (FunctionCode) {
853
854     case NETSHAREENUM:
855
856       Status = GSHORT(pd, loc_offset);
857
858       if (tree) {
859
860         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Status: %u", Status);
861
862       }
863
864       loc_offset += 2;
865
866       Convert = GSHORT(pd, loc_offset);
867
868       if (tree) {
869
870         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Convert: %u", Convert);
871
872       }
873
874       loc_offset += 2;
875
876       EntCount = GSHORT(pd, loc_offset);
877
878       if (tree) {
879
880         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Entry Count: %u", EntCount);
881
882       }
883
884       loc_offset += 2;
885
886       AvailCount = GSHORT(pd, loc_offset);
887
888       if (tree) {
889
890         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Available Entries: %u", AvailCount);
891
892       }
893
894       loc_offset += 2;
895
896       if (tree) {
897
898         ti = proto_tree_add_text(lanman_tree, NullTVB, loc_offset, AvailCount * 20, "Available Shares");
899
900         share_tree = proto_item_add_subtree(ti, ett_lanman_shares);
901
902       }
903
904       for (i = 1; i <= EntCount; i++) {
905         const gchar *Share = pd + loc_offset;
906         guint32     Flags;
907         const gchar *Comment;
908         proto_tree  *share = NULL;
909         proto_item  *ti = NULL;
910
911         if (tree) {
912
913           ti = proto_tree_add_text(share_tree, NullTVB, loc_offset, 20, "Share %s", Share);
914           share = proto_item_add_subtree(ti, ett_lanman_share);
915
916
917         }
918
919         if (tree) {
920           
921           proto_tree_add_text(share, NullTVB, loc_offset, 13, "Share Name: %s", Share);
922
923         }
924
925         loc_offset += 13;
926
927         loc_offset += 1;  /* Pad byte ... */
928
929         Flags = GSHORT(pd, loc_offset);
930
931         if (tree) {
932
933           proto_tree_add_text(share, NullTVB, loc_offset, 2, "Share Type: %s",
934                 val_to_str(Flags, share_type_vals, "Unknown (%u)"));
935
936         }
937
938         loc_offset += 2;
939
940         /* XXX - should check whether all of the string is within the
941            frame. */
942         string_offset = SMB_offset + DataOffset + (GWORD(pd, loc_offset) & 0xFFFF) - Convert;
943         if (IS_DATA_IN_FRAME(string_offset))
944           Comment = pd + string_offset;
945         else
946           Comment = "<String goes past end of frame>";
947
948         if (tree) {
949
950           proto_tree_add_text(share, NullTVB, loc_offset, 4, "Share Comment: %s", Comment);
951
952         }
953
954         loc_offset += 4;
955
956       }
957
958       break;
959
960     case NETSERVERENUM2:
961
962       Status = GSHORT(pd, loc_offset);
963
964       if (tree) {
965
966         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Status: %u", Status);
967
968       }
969
970       loc_offset += 2;
971
972       Convert = GSHORT(pd, loc_offset);
973
974       if (tree) {
975
976         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Convert: %u", Convert);
977
978       }
979
980       loc_offset += 2;
981
982       EntCount = GSHORT(pd, loc_offset);
983
984       if (tree) {
985
986         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Entry Count: %u", EntCount);
987
988       }
989
990       loc_offset += 2;
991
992       AvailCount = GSHORT(pd, loc_offset);
993
994       if (tree) {
995
996         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Available Entries: %u", AvailCount);
997
998       }
999
1000       loc_offset += 2;
1001
1002       if (tree) {
1003
1004         ti = proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 26 * AvailCount, "Servers");
1005         if (ti == NULL) { 
1006
1007           printf("Null value returned from proto_tree_add_text\n");
1008           exit(1);
1009
1010         }
1011
1012         server_tree = proto_item_add_subtree(ti, ett_lanman_servers);
1013
1014       }
1015
1016       /* Make sure we don't go past the end of the capture buffer */
1017
1018       for (i = 1; (i <= EntCount) && ((pi.captured_len - loc_offset) >= 16); i++) {
1019         const gchar *Server = pd + loc_offset;
1020         gint8       ServerMajor;
1021         guint       ServerMinor;
1022         guint32     ServerFlags;
1023         const gchar *Comment;
1024         proto_tree  *server = NULL;
1025         proto_item  *ti;
1026
1027         if (tree) {
1028
1029           ti = proto_tree_add_text(server_tree, NullTVB, loc_offset, 
1030                                    (si.request_val -> last_level) ? 26 : 16,
1031                                    "Server %s", Server);
1032           server = proto_item_add_subtree(ti, ett_lanman_server);
1033
1034
1035         }
1036
1037         if (tree) {
1038           
1039           proto_tree_add_text(server, NullTVB, loc_offset, 16, "Server Name: %s", Server);
1040
1041         }
1042
1043         loc_offset += 16;
1044
1045         if (si.request_val -> last_level) { /* Print out the rest of the info */
1046
1047           ServerMajor = GBYTE(pd, loc_offset);
1048
1049           if (tree) {
1050
1051             proto_tree_add_text(server, NullTVB, loc_offset, 1, "Major Version: %u", ServerMajor);
1052
1053           }
1054
1055           loc_offset += 1;
1056
1057           ServerMinor = GBYTE(pd, loc_offset);
1058
1059           if (tree) {
1060
1061             proto_tree_add_text(server, NullTVB, loc_offset, 1, "Minor Version: %u", ServerMinor);
1062
1063           }
1064
1065           loc_offset += 1;
1066
1067           ServerFlags = GWORD(pd, loc_offset);
1068
1069           if (tree) {
1070
1071             ti = proto_tree_add_text(server, NullTVB, loc_offset, 4, "Server Type: 0x%08X", ServerFlags);
1072             flags_tree = proto_item_add_subtree(ti, ett_lanman_flags);
1073             dissect_server_flags(flags_tree, loc_offset, 4, ServerFlags);
1074
1075           }
1076
1077           loc_offset += 4;
1078
1079           /* XXX - should check whether all of the string is within the
1080              frame. */
1081           string_offset = SMB_offset + DataOffset + (GWORD(pd, loc_offset) & 0xFFFF) - Convert;
1082           if (IS_DATA_IN_FRAME(string_offset))
1083             Comment = pd + string_offset;
1084           else
1085             Comment = "<String goes past end of frame>";
1086
1087           if (tree) {
1088
1089             proto_tree_add_text(server, NullTVB, loc_offset, 4, "Server Comment: %s", Comment);
1090
1091           }
1092
1093           loc_offset += 4;
1094
1095         }
1096
1097       }
1098
1099       break;
1100
1101     default:
1102
1103       Status = GSHORT(pd, loc_offset);
1104
1105       if (tree) {
1106
1107         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Status: %u", Status);
1108
1109       }
1110
1111       loc_offset += 2;
1112
1113       Convert = GSHORT(pd, loc_offset);
1114
1115       if (tree) {
1116
1117         proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Convert: %u", Convert);
1118
1119       }
1120
1121       loc_offset += 2;
1122
1123       if (tree) {
1124
1125         int i = 0;
1126         char *name = NULL;
1127
1128         dissect_transact_engine_init(pd, si.request_val -> last_param_descrip, si.request_val -> last_data_descrip, SMB_offset, loc_offset, ParameterCount, DataOffset, DataCount);
1129
1130         if (lanman) name = lanman -> resp[i];
1131           
1132         while (dissect_transact_next(pd, name, dirn, lanman_tree))
1133           if (name) name = lanman -> resp[++i];
1134           
1135       }
1136
1137       return TRUE;
1138       break;
1139
1140     }
1141
1142   }
1143
1144   return FALSE;
1145
1146 }
1147
1148 gboolean
1149 dissect_pipe_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn, const u_char *command, int DataOffset, int DataCount, int ParameterOffset, int ParameterCount)
1150 {
1151
1152   if (!proto_is_protocol_enabled(proto_smb_lanman))
1153     return FALSE;
1154
1155   if (command != NULL && strcmp(command, "LANMAN") == 0) {
1156     /* Try to decode a LANMAN */
1157
1158     return dissect_pipe_lanman(pd, offset, fd, parent, tree, si, max_data,
1159                                SMB_offset, errcode, dirn, command, DataOffset,
1160                                DataCount, ParameterOffset, ParameterCount);
1161
1162   }
1163
1164   return FALSE;
1165
1166 }
1167
1168 static void
1169 pipe_lanman_init_protocol(void)
1170 {
1171   if (lanman_proto_data != NULL)
1172     g_mem_chunk_destroy(lanman_proto_data);
1173
1174   lanman_proto_data = g_mem_chunk_new("lanman_proto_data",
1175                                       sizeof(response_data),
1176                                       100 * sizeof(response_data),
1177                                       G_ALLOC_AND_FREE);
1178 }
1179
1180 void
1181 register_proto_smb_pipe( void){
1182
1183
1184         static gint *ett[] = {
1185
1186                 &ett_lanman,
1187                 &ett_lanman_servers,
1188                 &ett_lanman_server,
1189                 &ett_lanman_shares,
1190                 &ett_lanman_share,
1191                 &ett_lanman_flags
1192         };
1193
1194
1195         proto_smb_lanman = proto_register_protocol(
1196                 "Microsoft Windows Lanman Protocol", "LANMAN", "lanman");
1197
1198         proto_register_subtree_array(ett, array_length(ett));
1199         register_init_routine(&pipe_lanman_init_protocol);
1200 }