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