Free the string you "g_strdup()"ed, rather than handing "g_free()" the
[obnox/wireshark/wip.git] / packet-smb-browse.c
1 /* packet-smb-browse.c
2  * Routines for SMB Browser packet dissection
3  * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
4  *
5  * $Id: packet-smb-browse.c,v 1.8 2001/03/18 03:34:22 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 #include "packet-smb-browse.h"
52
53 static int proto_smb_browse = -1;
54
55 static gint ett_browse = -1;
56 static gint ett_browse_flags = -1;
57 static gint ett_browse_election_criteria = -1;
58 static gint ett_browse_election_os = -1;
59 static gint ett_browse_election_desire = -1;
60
61
62
63 static char *browse_commands[] = 
64 { "Error, No such command!",       /* Value 0 */
65   "Host Announcement",             /* Value 1 */
66   "Request Announcement",          /* Value 2 */
67   "Error, No such command!",       /* Value 3 */
68   "Error, No such command!",       /* Value 4 */
69   "Error, No such command!",       /* Value 5 */
70   "Error, No such command!",       /* Value 6 */
71   "Error, No such command!",       /* Value 7 */
72   "Browser Election Request",      /* Value 8 */
73   "Get Backup List Request",       /* Value 9 */
74   "Get Backup List Response",      /* Value 10 */
75   "Become Backup Browser",         /* Value 11 */
76   "Domain/Workgroup Announcement", /* Value 12 */
77   "Master Announcement",           /* Value 13 */
78   "Error! No such command",        /* Value 14 */
79   "Local Master Announcement"      /* Value 15 */
80 };
81
82 #define HOST_ANNOUNCE        1
83 #define REQUEST_ANNOUNCE     2
84 #define BROWSER_ELECTION     8
85 #define GETBACKUPLISTREQ     9
86 #define GETBACKUPLISTRESP   10
87 #define BECOMEBACKUPBROWSER 11
88 #define DOMAINANNOUNCEMENT  12
89 #define MASTERANNOUNCEMENT  13
90 #define LOCALMASTERANNOUNC  15
91
92 static char *svr_types[32] = {
93   "Workstation",
94   "Server",
95   "SQL Server",
96   "Domain Controller",
97   "Backup Controller",
98   "Time Source",
99   "Apple Server",
100   "Novell Server",
101   "Domain Member Server",
102   "Print Queue Server",
103   "Dialin Server",
104   "Xenix Server",
105   "NT Workstation",
106   "Windows for Workgroups",
107   "Unknown Server - FIXME",
108   "NT Server",
109   "Potential Browser",
110   "Backup Browser",
111   "Master Browser",
112   "Domain Master Browser",
113   "OSF",
114   "VMS",
115   "Windows 95 or above",
116   "Unused",
117   "Unused",
118   "Unused",
119   "Unused",
120   "Unused",
121   "Unused",
122   "Unused",
123   "Local List Only",
124   "Domain Enum"
125 };
126
127 gboolean
128 dissect_mailslot_browse(const u_char *pd, int offset, frame_data *fd,
129     proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data,
130     int SMB_offset, int errcode, int dirn, const u_char *command,
131     int DataOffset, int DataCount)
132 {
133   guint8               OpCode;
134   guint8               UpdateCount;
135   guint8               VersionMajor;
136   guint8               VersionMinor;
137   guint32              Periodicity;
138   guint32              ServerType;
139   guint16              SigConstant;
140   guint32              Token;
141   guint8               BackupServerCount;
142   guint8               Flags;
143   guint32              MBZ;
144   guint8               ElectionVersion;
145   guint32              ElectionCriteria;
146   guint8               ElectionOS;
147   guint8               ElectionDesire;
148   guint16              ElectionRevision;
149   guint32              ServerUpTime;
150   const char           *ServerName;
151   const char           *ServerComment;
152   proto_tree           *browse_tree = NULL, *flags_tree = NULL, 
153                        *OSflags = NULL, *DesireFlags = NULL;
154   proto_item           *ti, *ec;
155   guint32              loc_offset = DataOffset, count = 0;
156   int                  i;
157
158   if (!proto_is_protocol_enabled(proto_smb_browse))
159     return FALSE;
160
161   if (check_col(fd, COL_PROTOCOL))
162     col_set_str(fd, COL_PROTOCOL, "BROWSER");
163
164   if (check_col(fd, COL_INFO)) /* Put in something, and replace it later */
165     col_set_str(fd, COL_INFO, "Browse Announcement");
166
167   /*
168    * Now, decode the browse request 
169    */
170
171   OpCode = GBYTE(pd, loc_offset);
172
173   if (check_col(fd, COL_INFO))
174     col_add_fstr(fd, COL_INFO, (OpCode > (sizeof(browse_commands)/sizeof(char *))) ? "Error, No Such Command:%u" : browse_commands[OpCode], OpCode);
175     
176   if (tree) {  /* Add the browse tree */
177
178     ti = proto_tree_add_item(parent, proto_smb_browse, NullTVB, DataOffset, DataCount, FALSE);
179     browse_tree = proto_item_add_subtree(ti, ett_browse);
180
181     proto_tree_add_text(browse_tree, NullTVB, loc_offset, 1, "OpCode: %s", (OpCode > (sizeof(browse_commands)/sizeof(char *))) ? "Error, No Such Command" : browse_commands[OpCode]);
182
183   }
184
185   loc_offset += 1;    /* Skip the OpCode */
186
187   switch (OpCode) {
188
189   case DOMAINANNOUNCEMENT:
190   case LOCALMASTERANNOUNC:
191   case HOST_ANNOUNCE:
192
193     UpdateCount = GBYTE(pd, loc_offset);
194
195     if (tree) {
196
197       proto_tree_add_text(browse_tree, NullTVB, loc_offset, 1, "Update Count: %u", UpdateCount);
198
199     }
200
201     loc_offset += 1;  /* Skip the Update Count */
202
203     Periodicity = GWORD(pd, loc_offset);
204
205     if (tree) {
206
207       proto_tree_add_text(browse_tree, NullTVB, loc_offset, 4, "Update Periodicity: %u Sec", Periodicity/1000 );
208
209     }
210
211     loc_offset += 4;
212
213     ServerName = pd + loc_offset;
214
215     if (check_col(fd, COL_INFO)) {
216
217       col_append_fstr(fd, COL_INFO, " %s", ServerName);
218
219     }
220
221     if (tree) {
222
223       proto_tree_add_text(browse_tree, NullTVB, loc_offset, 16, (OpCode == DOMAINANNOUNCEMENT) ? "Domain/WorkGroup: %s": "Host Name: %s", ServerName);
224
225     }
226
227     loc_offset += 16;
228
229     VersionMajor = GBYTE(pd, loc_offset);
230
231     if (tree) {
232
233       proto_tree_add_text(browse_tree, NullTVB, loc_offset, 1, "Major Version: %u", VersionMajor);
234
235     }
236
237     loc_offset += 1;
238
239     VersionMinor = GBYTE(pd, loc_offset);
240
241     if (tree) {
242
243       proto_tree_add_text(browse_tree, NullTVB, loc_offset, 1, "Minor Version: %u", VersionMinor);
244
245     }
246
247     loc_offset += 1;
248
249     ServerType = GWORD(pd, loc_offset);
250
251     if (check_col(fd, COL_INFO)) {
252
253       /* Append the type(s) of the system to the COL_INFO line ... */
254
255       for (i = 0; i < 32; i++) {
256
257         if (ServerType & (1 << i) && (strcmp("Unused", svr_types[i]) != 0))
258             col_append_fstr(fd, COL_INFO, ", %s", svr_types[i]);
259         
260       }
261       
262     }
263
264     if (tree) {
265
266       ti = proto_tree_add_text(browse_tree, NullTVB, loc_offset, 4, "Server Type: 0x%04x", ServerType);
267       flags_tree = proto_item_add_subtree(ti, ett_browse_flags);
268       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
269                           decode_boolean_bitfield(ServerType, 0x0001, 32, "Workstation", "Not Workstation"));
270       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
271                           decode_boolean_bitfield(ServerType, 0x0002, 32, "Server", "Not Server"));
272       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
273                           decode_boolean_bitfield(ServerType, 0x0004, 32, "SQL Server", "Not SQL Server"));
274       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
275                           decode_boolean_bitfield(ServerType, 0x0008, 32, "Domain Controller", "Not Domain Controller"));
276       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
277                           decode_boolean_bitfield(ServerType, 0x0010, 32, "Backup Controller", "Not Backup Controller"));
278       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
279                           decode_boolean_bitfield(ServerType, 0x0020, 32, "Time Source", "Not Time Source"));
280       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
281                           decode_boolean_bitfield(ServerType, 0x0040, 32, "Apple Server", "Not Apple Server"));
282       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
283                           decode_boolean_bitfield(ServerType, 0x0080, 32, "Novell Server", "Not Novell Server"));
284       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
285                           decode_boolean_bitfield(ServerType, 0x0100, 32, "Domain Member Server", "Not Domain Member Server"));
286       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
287                           decode_boolean_bitfield(ServerType, 0x0200, 32, "Print Queue Server", "Not Print Queue Server"));      
288       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
289                           decode_boolean_bitfield(ServerType, 0x0400, 32, "Dialin Server", "Not Dialin Server"));
290       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
291                           decode_boolean_bitfield(ServerType, 0x0800, 32, "Xenix Server", "Not Xenix Server"));
292       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
293                           decode_boolean_bitfield(ServerType, 0x1000, 32, "NT Workstation", "Not NT Workstation"));
294       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
295                           decode_boolean_bitfield(ServerType, 0x2000, 32, "Windows for Workgroups", "Not Windows for Workgroups"));
296       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
297                           decode_boolean_bitfield(ServerType, 0x8000, 32, "NT Server", "Not NT Server"));
298       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
299                           decode_boolean_bitfield(ServerType, 0x10000, 32, "Potential Browser", "Not Potential Browser"));
300       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
301                           decode_boolean_bitfield(ServerType, 0x20000, 32, "Backup Browser", "Not Backup Browser"));
302       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
303                           decode_boolean_bitfield(ServerType, 0x40000, 32, "Master Browser", "Not Master Browser"));
304       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
305                           decode_boolean_bitfield(ServerType, 0x80000, 32, "Domain Master Browser", "Not Domain Master Browser"));
306       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
307                           decode_boolean_bitfield(ServerType, 0x100000, 32, "OSF", "Not OSF"));
308       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
309                           decode_boolean_bitfield(ServerType, 0x200000, 32, "VMS", "Not VMS"));
310       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
311                           decode_boolean_bitfield(ServerType, 0x400000, 32, "Windows 95 or above", "Not Windows 95 or above"));
312       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
313                           decode_boolean_bitfield(ServerType, 0x40000000, 32, "Local List Only", "Not Local List Only"));
314       proto_tree_add_text(flags_tree, NullTVB, loc_offset, 4, "%s",
315                           decode_boolean_bitfield(ServerType, 0x80000000, 32, "Domain Enum", "Not Domain Enum"));
316     }
317     loc_offset += 4;
318     
319     ElectionVersion = GSHORT(pd, loc_offset);
320     
321     if (tree) {
322       
323       proto_tree_add_text(browse_tree, NullTVB, loc_offset, 2, "Election Version: %u", ElectionVersion);
324
325     }
326
327     loc_offset += 2;
328
329     SigConstant = GSHORT(pd, loc_offset);
330
331     if (tree) {
332
333       proto_tree_add_text(browse_tree, NullTVB, loc_offset, 2, "Signature: %u (0x%04X)", SigConstant, SigConstant);
334
335     }
336
337     loc_offset += 2;
338
339     ServerComment = pd + loc_offset;
340
341     if (tree) {
342
343       proto_tree_add_text(browse_tree, NullTVB, loc_offset, strlen(ServerComment) + 1, "Host Comment: %s", ServerComment);
344
345     }
346
347     break;
348
349   case REQUEST_ANNOUNCE:
350
351     Flags = GBYTE(pd, loc_offset);
352
353     if (tree) {
354
355       proto_tree_add_text(browse_tree, NullTVB, loc_offset, 1, "Unused Flags: %u", Flags);
356
357     }
358
359     loc_offset += 1;
360
361     ServerName = pd + loc_offset;
362
363     if (tree) {
364
365       proto_tree_add_text(browse_tree, NullTVB, loc_offset, strlen(ServerName) + 1, "Send List To: %s", ServerName);
366
367     }
368
369     break;
370
371   case BROWSER_ELECTION:
372
373     ElectionVersion = GBYTE(pd, loc_offset);
374
375     if (tree) {
376
377       proto_tree_add_text(browse_tree, NullTVB, loc_offset, 1, "Election Version = %u", ElectionVersion);
378
379     }
380
381     loc_offset += 1;
382
383     ElectionCriteria = GWORD(pd, loc_offset);
384     ElectionOS       = GBYTE(pd, loc_offset + 3);
385     ElectionRevision = GSHORT(pd, loc_offset + 1);
386     ElectionDesire   = GBYTE(pd, loc_offset);
387
388     if (tree) {
389
390       ti = proto_tree_add_text(browse_tree, NullTVB, loc_offset, 4, "Election Criteria = %u (0x%08X)", ElectionCriteria, ElectionCriteria);
391
392       ec = proto_item_add_subtree(ti, ett_browse_election_criteria);
393
394       ti = proto_tree_add_text(ec, NullTVB, loc_offset + 3, 1, "Election OS Summary: %u (0x%02X)", ElectionOS, ElectionOS);
395
396       OSflags = proto_item_add_subtree(ti, ett_browse_election_os);
397
398       proto_tree_add_text(OSflags, NullTVB, loc_offset + 3, 1, "%s",
399                             decode_boolean_bitfield(ElectionOS, 0x01, 8, "Windows for Workgroups", "Not Windows for Workgroups"));
400       
401       proto_tree_add_text(OSflags, NullTVB, loc_offset + 3, 1, "%s",
402                           decode_boolean_bitfield(ElectionOS, 0x02, 8, "Unknown", "Not used"));
403
404       proto_tree_add_text(OSflags, NullTVB, loc_offset + 3, 1, "%s",
405                           decode_boolean_bitfield(ElectionOS, 0x04, 8, "Unknown", "Not used"));
406
407       proto_tree_add_text(OSflags, NullTVB, loc_offset + 3, 1, "%s",
408                           decode_boolean_bitfield(ElectionOS, 0x08, 8, "Unknown", "Not used"));
409       
410       proto_tree_add_text(OSflags, NullTVB, loc_offset + 3, 1, "%s",
411                           decode_boolean_bitfield(ElectionOS, 0x10, 8, "Windows NT Workstation", "Not Windows NT Workstation"));
412       
413       proto_tree_add_text(OSflags, NullTVB, loc_offset + 3, 1, "%s",
414                           decode_boolean_bitfield(ElectionOS, 0x20, 8, "Windows NT Server", "Not Windows NT Server"));
415
416       proto_tree_add_text(OSflags, NullTVB, loc_offset + 3, 1, "%s",
417                           decode_boolean_bitfield(ElectionOS, 0x40, 8, "Unknown", "Not used"));
418
419       proto_tree_add_text(OSflags, NullTVB, loc_offset + 3, 1, "%s",
420                           decode_boolean_bitfield(ElectionOS, 0x80, 8, "Unknown", "Not used"));
421
422       proto_tree_add_text(ec, NullTVB, loc_offset + 1, 2, "Election Revision: %u (0x%04X)", ElectionRevision, ElectionRevision);
423
424       ti = proto_tree_add_text(ec, NullTVB, loc_offset, 1, "Election Desire Summary: %u (0x%02X)", ElectionDesire, ElectionDesire);
425
426       DesireFlags = proto_item_add_subtree(ti, ett_browse_election_desire);
427
428       proto_tree_add_text(DesireFlags, NullTVB, loc_offset, 1, "%s",
429                           decode_boolean_bitfield(ElectionDesire, 0x01, 8, "Backup Browse Server", "Not Backup Browse Server"));
430       
431       proto_tree_add_text(DesireFlags, NullTVB, loc_offset, 1, "%s",
432                           decode_boolean_bitfield(ElectionDesire, 0x02, 8, "Standby Browse Server", "Not Standby Browse Server"));
433
434       proto_tree_add_text(DesireFlags, NullTVB, loc_offset, 1, "%s",
435                           decode_boolean_bitfield(ElectionDesire, 0x04, 8, "Master Browser", "Not Master Browser"));
436
437       proto_tree_add_text(DesireFlags, NullTVB, loc_offset, 1, "%s",
438                           decode_boolean_bitfield(ElectionDesire, 0x08, 8, "Domain Master Browse Server", "Not Domain Master Browse Server"));
439
440       proto_tree_add_text(DesireFlags, NullTVB, loc_offset, 1, "%s",
441                           decode_boolean_bitfield(ElectionDesire, 0x10, 8, "Unknown", "Not used"));
442
443       proto_tree_add_text(DesireFlags, NullTVB, loc_offset, 1, "%s",
444                           decode_boolean_bitfield(ElectionDesire, 0x20, 8, "WINS Client", "Not WINS Client"));
445
446       proto_tree_add_text(DesireFlags, NullTVB, loc_offset, 1, "%s",
447                           decode_boolean_bitfield(ElectionDesire, 0x40, 8, "Unknown", "Not used"));
448
449       proto_tree_add_text(DesireFlags, NullTVB, loc_offset, 1, "%s",
450                           decode_boolean_bitfield(ElectionDesire, 0x80, 8, "Windows NT Advanced Server", "Not Windows NT Advanced Server"));
451
452     }
453
454     loc_offset += 4;
455
456     ServerUpTime = GWORD(pd, loc_offset);
457
458     if (tree) {
459
460       proto_tree_add_text(browse_tree, NullTVB, loc_offset, 4, "Server Up Time: %u Sec (%ums)", ServerUpTime/1000, ServerUpTime);
461
462     }
463
464     loc_offset += 4;
465
466     MBZ = GWORD(pd, loc_offset);
467
468     loc_offset += 4;
469
470     ServerName = pd + loc_offset;
471
472     if (tree) {
473
474       proto_tree_add_text(browse_tree, NullTVB, loc_offset, strlen(ServerName) + 1, "Election Server Name: %s", ServerName);
475
476     }
477
478     break;
479
480   case GETBACKUPLISTREQ:
481
482     BackupServerCount = GBYTE(pd, loc_offset);
483
484     if (tree) {
485
486       proto_tree_add_text(browse_tree, NullTVB, loc_offset, 1, "Backup List Requested Count: %u", BackupServerCount);
487
488     }
489
490     loc_offset += 1;
491
492     Token = GWORD(pd, loc_offset);
493
494     if (tree) {
495
496       proto_tree_add_text(browse_tree, NullTVB, loc_offset, 4, "Backup Request Token: %u", Token);
497
498     }
499
500     break;
501
502   case GETBACKUPLISTRESP:
503
504     BackupServerCount = GBYTE(pd, loc_offset);
505
506     if (tree) {
507
508       proto_tree_add_text(browse_tree, NullTVB, loc_offset, 1, "Backup Server Count: %u", BackupServerCount);
509
510     }
511
512     loc_offset += 1;
513
514     Token = GWORD(pd, loc_offset);
515
516     if (tree) {
517
518       proto_tree_add_text(browse_tree, NullTVB, loc_offset, 4, "Backup Response Token: %u", Token);
519
520     }
521
522     loc_offset += 4;
523
524     ServerName = pd + loc_offset;
525
526     for (count = 1; count <= BackupServerCount; count++) {
527
528       if (tree) {
529
530         proto_tree_add_text(browse_tree, NullTVB, loc_offset, strlen(ServerName) + 1, "Backup Server: %s", ServerName);
531
532       }
533
534       loc_offset += strlen(ServerName) + 1;
535
536       ServerName = pd + loc_offset;
537
538     }
539
540     break;
541
542   case BECOMEBACKUPBROWSER:
543
544     ServerName = pd + loc_offset;
545
546     if (tree) {
547
548       proto_tree_add_text(browse_tree, NullTVB, loc_offset, strlen(ServerName) + 1, "Browser to Promote: %s", ServerName);
549
550     }
551
552     break;
553
554   case MASTERANNOUNCEMENT:
555
556     ServerName = pd + loc_offset;
557
558     if (tree) {
559
560       proto_tree_add_text(browse_tree, NullTVB, loc_offset, strlen(ServerName) + 1, "Server Name: %s", ServerName);
561
562     }
563
564     break;
565
566   default:
567     break;
568   }
569   
570   return TRUE;  /* Success */
571
572 }
573
574
575 void
576 register_proto_smb_browse( void){
577
578
579         static gint *ett[] = {
580                 &ett_browse,
581                 &ett_browse_flags,
582                 &ett_browse_election_criteria,
583                 &ett_browse_election_os,
584                 &ett_browse_election_desire
585         };
586
587         proto_smb_browse = proto_register_protocol("Microsoft Windows Browser Protocol",
588             "BROWSER", "browser");
589
590         proto_register_subtree_array(ett, array_length(ett));          
591 }