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