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