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