1 
2 /* These are all functions from ethereal, just as they are there */
3 
4 /* packet-nbns.c
5  * Routines for NetBIOS-over-TCP packet disassembly (the name dates back
6  * to when it had only NBNS)
7  * Gilbert Ramirez <gram@verdict.uthscsa.edu>
8  * Much stuff added by Guy Harris <guy@netapp.com>
9  *
10  *
11  * Ethereal - Network traffic analyzer
12  * By Gerald Combs <gerald@zing.org>
13  * Copyright 1998 Gerald Combs
14  *
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 
35 #include "names_netbios.h"
36 #include "stats/util.h"
37 
38 #define NBNAME_BUF_LEN               128
39 #define BYTES_ARE_IN_FRAME(a, b, c)  (((a)+(b)) < (c))
40 
41 
42 typedef struct
43 {
44   int number;
45   gchar *name;
46 } value_string;
47 
48 static const value_string name_type_vals[] = {
49   {0x00, "Workstation/Redirector"},
50   {0x01, "Browser"},
51   {0x02, "Workstation/Redirector"},
52   /* not sure what 0x02 is, I'm seeing alot of them however */
53   /* i'm seeing them with workstation/redirection host
54      announcements */
55   {0x03, "Messenger service/Main name"},
56   {0x05, "Forwarded name"},
57   {0x06, "RAS Server service"},
58   {0x1b, "PDC Domain name"},
59   {0x1c, "BDC Domain name"},
60   {0x1d, "Master Browser backup"},
61   {0x1e, "Browser Election Service"},
62   {0x1f, "Net DDE Service"},
63   {0x20, "Server service"},
64   {0x21, "RAS client service"},
65   {0x22, "Exchange Interchange (MSMail Connector)"},
66   {0x23, "Exchange Store"},
67   {0x24, "Exchange Directory"},
68   {0x2b, "Lotus Notes Server service"},
69   {0x30, "Modem sharing server service"},
70   {0x31, "Modem sharing client service"},
71   {0x43, "SMS Clients Remote Control"},
72   {0x44, "SMS Administrators Remote Control Tool"},
73   {0x45, "SMS Clients Remote Chat"},
74   {0x46, "SMS Clients Remote Transfer"},
75   {0x4c, "DEC Pathworks TCP/IP Service on Windows NT"},
76   {0x52, "DEC Pathworks TCP/IP Service on Windows NT"},
77   {0x6a, "Microsoft Exchange IMC"},
78   {0x87, "Microsoft Exchange MTA"},
79   {0xbe, "Network Monitor Agent"},
80   {0xbf, "Network Monitor Analyzer"},
81   {0x00, NULL}
82 };
83 
84 
85 /***************************************************************************
86  *
87  * local function definitions
88  *
89  **************************************************************************/
90 static int get_dns_name(const gchar *pd, int offset, int pd_len, char *name, int maxname);
91 static int process_netbios_name(const gchar *name_ptr, char *name_ret, size_t maxname);
92 
93 
94 /***************************************************************************
95  *
96  * implementation
97  *
98  **************************************************************************/
get_dns_name(const gchar * pd,int offset,int pd_len,char * name,int maxname)99 static int get_dns_name(const gchar *pd, int offset, int pd_len, char *name, int maxname)
100 {
101   const gchar *dp = pd + offset;
102   const gchar *dptr = dp;
103   char *np = name;
104   int len = -1;
105   unsigned int component_len;
106   int dns_data_offset;
107 
108   if (offset >= pd_len)
109     goto overflow;
110 
111   dns_data_offset = offset;
112 
113   maxname--;                    /* reserve space for the trailing '\0' */
114   for (;;) {
115     if (!BYTES_ARE_IN_FRAME(offset, 1, pd_len))
116       goto overflow;
117     component_len = *dp++;
118     offset++;
119     if (component_len == 0)
120       break;
121     switch (component_len & 0xc0)
122     {
123         case 0x00:
124           /* Label */
125           if (np != name) {
126             /* Not the first component - put in a '.'. */
127             if (maxname > 0) {
128               *np++ = '.';
129               maxname--;
130             }
131           }
132           if (!BYTES_ARE_IN_FRAME(offset, component_len, pd_len))
133             goto overflow;
134           while (component_len > 0) {
135             if (maxname > 0) {
136               *np++ = *dp;
137               maxname--;
138             }
139             component_len--;
140             dp++;
141             offset++;
142           }
143           break;
144 
145         case 0x40:
146         case 0x80:
147           goto dns_name_terminated;             /* error */
148 
149         case 0xc0:
150           /* Pointer. */
151           /* XXX - check to make sure we aren't looping, by keeping track
152              of how many characters are in the DNS packet, and of how many
153              characters we've looked at, and quitting if the latter
154              becomes bigger than the former. */
155           if (!BYTES_ARE_IN_FRAME(offset, 1, pd_len))
156             goto overflow;
157           offset =
158             dns_data_offset + (((component_len & ~0xc0) << 8) | (*dp++));
159           /* If "len" is negative, we are still working on the original name,
160              not something pointed to by a pointer, and so we should set "len"
161              to the length of the original name. */
162           if (len < 0)
163             len = dp - dptr;
164           dp = pd + offset;
165           break;                /* now continue processing from there */
166     }
167   }
168 
169 dns_name_terminated:
170   *np = '\0';
171   /* If "len" is negative, we haven't seen a pointer, and thus haven't
172      set the length, so set it. */
173   if (len < 0)
174     len = dp - dptr;
175   /* Zero-length name means "root server" */
176   if (*name == '\0')
177     safe_strncpy(name, "<Root>", maxname);
178   return len;
179 
180 overflow:
181   /* We ran past the end of the captured data in the packet. */
182   safe_strncpy(name, "<Name goes past end of captured data in packet>", maxname);
183   /* If "len" is negative, we haven't seen a pointer, and thus haven't
184      set the length, so set it. */
185   if (len < 0)
186     len = dp - dptr;
187   return len;
188 }
189 
process_netbios_name(const gchar * name_ptr,char * outname,size_t outname_size)190 static int process_netbios_name(const gchar *name_ptr, char *outname, size_t outname_size)
191 {
192   unsigned int i;
193   int name_type = *(name_ptr + NETBIOS_NAME_LEN - 1);
194   gchar name_char;
195   char *name_ret;
196   static const char hex_digits[16] = "0123456780abcdef";
197 
198   name_ret = outname;
199   for (i = 0;
200        i < NETBIOS_NAME_LEN - 1 && name_ret-outname < outname_size-1;
201        ++i) {
202     name_char = *name_ptr++;
203     if (name_char >= ' ' && name_char <= '~')
204       *name_ret++ = name_char;
205     else {
206       /* It's not printable; show it as <XX>, where
207          XX is the value in hex. */
208       *name_ret++ = '<';
209       *name_ret++ = hex_digits[(name_char >> 4)];
210       *name_ret++ = hex_digits[(name_char & 0x0F)];
211       *name_ret++ = '>';
212     }
213   }
214   *name_ret = '\0';
215   return name_type;
216 }
217 
ethereal_nbns_name(const gchar * pd,int offset,int pd_len,char * outname,size_t outname_size,int * name_type_ret)218 int ethereal_nbns_name(const gchar *pd, int offset, int pd_len,
219                        char *outname, size_t outname_size,
220                        int *name_type_ret)
221 {
222   int name_len;
223   char name[MAXDNAME];
224   char nbname[NBNAME_BUF_LEN];
225   char buf[16];
226   char *pname, *pnbname, cname, cnbname;
227   int name_type;
228 
229   name_len = get_dns_name(pd, offset, pd_len, name, sizeof(name));
230 
231   /* OK, now undo the first-level encoding. */
232   pname = &name[0];
233   pnbname = &nbname[0];
234   for (;;) {
235     /* Every two characters of the first level-encoded name
236      * turn into one character in the decoded name. */
237     cname = *pname;
238     if (cname == '\0')
239       break; /* no more characters */
240     if (cname == '.')
241       break; /* scope ID follows */
242     if (cname < 'A' || cname > 'Z') {
243       /* Not legal. */
244       safe_strncpy(nbname,
245                    "Illegal NetBIOS name (character not between A and Z in first-level encoding)",
246                    sizeof(nbname));
247       goto bad;
248     }
249     cname -= 'A';
250     cnbname = cname << 4;
251     pname++;
252 
253     cname = *pname;
254     if (cname == '\0' || cname == '.') {
255       /* No more characters in the name - but we're in
256        * the middle of a pair.  Not legal. */
257       safe_strncpy(nbname, "Illegal NetBIOS name (odd number of bytes)", sizeof(nbname));
258       goto bad;
259     }
260     if (cname < 'A' || cname > 'Z') {
261       /* Not legal. */
262       safe_strncpy(nbname,
263                    "Illegal NetBIOS name (character not between A and Z in first-level encoding)",
264                    sizeof(nbname));
265       goto bad;
266     }
267     cname -= 'A';
268     cnbname |= cname;
269     pname++;
270 
271     /* Do we have room to store the character? */
272     if (pnbname < &nbname[NETBIOS_NAME_LEN]) {
273       /* Yes - store the character. */
274       *pnbname = cnbname;
275     }
276 
277     /* We bump the pointer even if it's past the end of the
278        name, so we keep track of how long the name is. */
279     pnbname++;
280   }
281 
282   /* NetBIOS names are supposed to be exactly 16 bytes long. */
283   if (pnbname - nbname != NETBIOS_NAME_LEN) {
284     /* It's not. */
285     snprintf(nbname, sizeof(nbname), "Illegal NetBIOS name (%ld bytes long)",
286              (long)(pnbname - nbname));
287     goto bad;
288   }
289 
290   /* This one is; make its name printable. */
291   name_type = process_netbios_name(nbname, outname, outname_size);
292   snprintf(buf, sizeof(buf), "<%02x>", name_type);
293 
294   safe_strncat(outname, buf, outname_size);
295   if (cname == '.') {
296     /* We have a scope ID, starting at "pname"; append that to
297      * the decoded host name. */
298     safe_strncat(outname, pname, outname_size);
299   }
300   if (name_type_ret != NULL)
301     *name_type_ret = name_type;
302   return name_len;
303 
304 bad:
305   if (name_type_ret != NULL)
306     *name_type_ret = -1;
307   safe_strncpy(outname, nbname, outname_size);
308   return name_len;
309 }
310 
311 
312 /* My only code here (JTC) */
313 
get_netbios_host_type(int type)314 gchar *get_netbios_host_type(int type)
315 {
316   guint i = 0;
317 
318   while (name_type_vals[i].number || name_type_vals[i].name) {
319     if (name_type_vals[i].number == type)
320       return name_type_vals[i].name;
321     i++;
322   }
323 
324   return "Unknown";
325 }                               /* get_netbios_host_type */
326