various string related changes, mainly replace sprintf/snprintf by g_snprintf
[obnox/wireshark/wip.git] / packet-smb-common.c
1 /* packet-smb-common.c
2  * Common routines for smb packet dissection
3  * Copyright 2000, Jeffrey C. Foster <jfoste@woodward.com>
4  *
5  * $Id: packet-smb-common.c,v 1.19 2004/01/05 19:31:44 ulfl Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
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 #include "packet-smb-common.h"
29
30 /*
31  * Share type values - used in LANMAN and in SRVSVC.
32  *
33  * XXX - should we dissect share type values, at least in SRVSVC, as
34  * a subtree with bitfields, as the 0x80000000 bit appears to be a
35  * hidden bit, with some number of bits at the bottom being the share
36  * type?
37  *
38  * Does LANMAN use that bit?
39  */
40 const value_string share_type_vals[] = {
41         {0, "Directory tree"},
42         {1, "Printer queue"},
43         {2, "Communications device"},
44         {3, "IPC"},
45         {0x80000000, "Hidden Directory tree"},
46         {0x80000001, "Hidden Printer queue"},
47         {0x80000002, "Hidden Communications device"},
48         {0x80000003, "Hidden IPC"},
49         {0, NULL}
50 };
51
52 int display_ms_string(tvbuff_t *tvb, proto_tree *tree, int offset, int hf_index, char **data)
53 {
54         char *str;
55         gint len;
56
57         /* display a string from the tree and return the new offset */
58
59         str = tvb_get_stringz(tvb, offset, &len);
60         proto_tree_add_string(tree, hf_index, tvb, offset, len, str);
61
62         /* Return a copy of the string if requested */
63
64         if (data)
65                 *data = str;
66         else
67                 g_free(str);
68
69         return  offset+len;
70 }
71
72
73 int display_unicode_string(tvbuff_t *tvb, proto_tree *tree, int offset, int hf_index, char **data)
74 {
75         char *str, *p;
76         int len;
77         int charoffset;
78         guint16 character;
79
80         /* display a unicode string from the tree and return new offset */
81
82         /*
83          * Get the length of the string.
84          * XXX - is it a bug or a feature that this will throw an exception
85          * if we don't find the '\0'?  I think it's a feature.
86          */
87         len = 0;
88         while ((character = tvb_get_letohs(tvb, offset + len)) != '\0')
89                 len += 2;
90         len += 2;       /* count the '\0' too */
91
92         /*
93          * Allocate a buffer for the string; "len" is the length in
94          * bytes, not the length in characters.
95          */
96         str = g_malloc(len/2);
97
98         /*
99          * XXX - this assumes the string is just ISO 8859-1; we need
100          * to better handle multiple character sets in Ethereal,
101          * including Unicode/ISO 10646, and multiple encodings of
102          * that character set (UCS-2, UTF-8, etc.).
103          */
104         charoffset = offset;
105         p = str;
106         while ((character = tvb_get_letohs(tvb, charoffset)) != '\0') {
107                 *p++ = (char) character;
108                 charoffset += 2;
109         }
110         *p = '\0';
111
112         proto_tree_add_string(tree, hf_index, tvb, offset, len, str);
113
114         if (data)
115                 *data = str;
116         else
117                 g_free(str);
118
119         return  offset+len;
120 }
121
122 /* Max string length for displaying Unicode strings.  */
123 #define MAX_UNICODE_STR_LEN     256
124
125 /* Turn a little-endian Unicode '\0'-terminated string into a string we
126    can display.
127    XXX - for now, we just handle the ISO 8859-1 characters.
128    If exactlen==TRUE then us_lenp contains the exact len of the string in
129    bytes. It might not be null terminated !
130    bc specifies the number of bytes in the byte parameters; Windows 2000,
131    at least, appears, in some cases, to put only 1 byte of 0 at the end
132    of a Unicode string if the byte count
133 */
134 static gchar *
135 unicode_to_str(tvbuff_t *tvb, int offset, int *us_lenp, gboolean exactlen,
136                    guint16 bc)
137 {
138   static gchar  str[3][MAX_UNICODE_STR_LEN+3+1];
139   static gchar *cur;
140   gchar        *p;
141   guint16       uchar;
142   int           len;
143   int           us_len;
144   int           overflow = 0;
145
146   if (cur == &str[0][0]) {
147     cur = &str[1][0];
148   } else if (cur == &str[1][0]) {
149     cur = &str[2][0];
150   } else {
151     cur = &str[0][0];
152   }
153   p = cur;
154   len = MAX_UNICODE_STR_LEN;
155   us_len = 0;
156   for (;;) {
157     if (bc == 0)
158       break;
159     if (bc == 1) {
160       /* XXX - explain this */
161       if (!exactlen)
162         us_len += 1;    /* this is a one-byte null terminator */
163       break;
164     }
165     uchar = tvb_get_letohs(tvb, offset);
166     if (uchar == 0) {
167       us_len += 2;      /* this is a two-byte null terminator */
168       break;
169     }
170     if (len > 0) {
171       if ((uchar & 0xFF00) == 0)
172         *p++ = (gchar) uchar;   /* ISO 8859-1 */
173       else
174         *p++ = '?';     /* not 8859-1 */
175       len--;
176     } else
177       overflow = 1;
178     offset += 2;
179     bc -= 2;
180     us_len += 2;
181     if(exactlen){
182       if(us_len>= *us_lenp){
183         break;
184       }
185     }
186   }
187   if (overflow) {
188     /* Note that we're not showing the full string.  */
189     *p++ = '.';
190     *p++ = '.';
191     *p++ = '.';
192   }
193   *p = '\0';
194   *us_lenp = us_len;
195   return cur;
196 }
197
198 /* nopad == TRUE : Do not add any padding before this string
199  * exactlen == TRUE : len contains the exact len of the string in bytes.
200  * bc: pointer to variable with amount of data left in the byte parameters
201  *   region
202  */
203 const gchar *
204 get_unicode_or_ascii_string(tvbuff_t *tvb, int *offsetp,
205     gboolean useunicode, int *len, gboolean nopad, gboolean exactlen,
206     guint16 *bcp)
207 {
208   static gchar  str[3][MAX_UNICODE_STR_LEN+3+1];
209   static gchar *cur;
210   const gchar *string;
211   int string_len;
212   unsigned int copylen;
213
214   if (*bcp == 0) {
215     /* Not enough data in buffer */
216     return NULL;
217   }
218   if (useunicode) {
219     if ((!nopad) && (*offsetp % 2)) {
220       /*
221        * XXX - this should be an offset relative to the beginning of the SMB,
222        * not an offset relative to the beginning of the frame; if the stuff
223        * before the SMB has an odd number of bytes, an offset relative to
224        * the beginning of the frame will give the wrong answer.
225        */
226       (*offsetp)++;   /* Looks like a pad byte there sometimes */
227       (*bcp)--;
228       if (*bcp == 0) {
229         /* Not enough data in buffer */
230         return NULL;
231       }
232     }
233     if(exactlen){
234       string_len = *len;
235     }
236     string = unicode_to_str(tvb, *offsetp, &string_len, exactlen, *bcp);
237   } else {
238     if(exactlen){
239       /*
240        * The string we return must be null-terminated.
241        */
242       if (cur == &str[0][0]) {
243         cur = &str[1][0];
244       } else if (cur == &str[1][0]) {
245         cur = &str[2][0];
246       } else {
247         cur = &str[0][0];
248       }
249       copylen = *len;
250       if (copylen > MAX_UNICODE_STR_LEN)
251         copylen = MAX_UNICODE_STR_LEN;
252       tvb_memcpy(tvb, (guint8 *)cur, *offsetp, copylen);
253       cur[copylen] = '\0';
254       if (copylen > MAX_UNICODE_STR_LEN)
255         strcat(cur, "...");
256       string_len = *len;
257       string = cur;
258     } else {
259       string_len = tvb_strsize(tvb, *offsetp);
260       string = tvb_get_ptr(tvb, *offsetp, string_len);
261     }
262   }
263   *len = string_len;
264   return string;
265 }
266
267 int
268 dissect_smb_unknown(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset)
269 {
270         /* display data as unknown */
271
272         proto_tree_add_text(tree, tvb, offset, -1, "Data (%u bytes)",
273             tvb_reported_length_remaining(tvb, offset));
274
275         return offset+tvb_length_remaining(tvb, offset);
276 }
277
278 /* Dissect a NTLM response. This is documented at
279    http://ubiqx.org/cifs/SMB.html#8, para 2.8.5.3 */
280
281 static int hf_ntlmv2_response = -1;
282 static int hf_ntlmv2_response_hmac = -1;
283 static int hf_ntlmv2_response_header = -1;
284 static int hf_ntlmv2_response_reserved = -1;
285 static int hf_ntlmv2_response_time = -1;
286 static int hf_ntlmv2_response_chal = -1;
287 static int hf_ntlmv2_response_unknown = -1;
288 static int hf_ntlmv2_response_name = -1;
289 static int hf_ntlmv2_response_name_type = -1;
290 static int hf_ntlmv2_response_name_len = -1;
291
292 static gint ett_ntlmv2_response = -1;
293 static gint ett_ntlmv2_response_name = -1;
294
295 /* Name types */
296
297 const value_string ntlm_name_types[] = {
298         { NTLM_NAME_END, "End of list" },
299         { NTLM_NAME_NB_HOST, "NetBIOS host name" },
300         { NTLM_NAME_NB_DOMAIN, "NetBIOS domain name" },
301         { NTLM_NAME_DNS_HOST, "DNS host name" },
302         { NTLM_NAME_DNS_DOMAIN, "DNS domain name" },
303         { 0, NULL }
304 };
305
306 int
307 dissect_ntlmv2_response(tvbuff_t *tvb, proto_tree *tree, int offset, int len)
308 {
309         proto_item *ntlmv2_item = NULL;
310         proto_tree *ntlmv2_tree = NULL;
311
312         /* Dissect NTLMv2 bits&pieces */
313
314         if (tree) {
315                 ntlmv2_item = proto_tree_add_item(
316                         tree, hf_ntlmv2_response, tvb, 
317                         offset, len, TRUE);
318                 ntlmv2_tree = proto_item_add_subtree(
319                         ntlmv2_item, ett_ntlmv2_response);
320         }
321
322         proto_tree_add_item(
323                 ntlmv2_tree, hf_ntlmv2_response_hmac, tvb,
324                 offset, 16, TRUE);
325
326         offset += 16;
327
328         proto_tree_add_item(
329                 ntlmv2_tree, hf_ntlmv2_response_header, tvb,
330                 offset, 4, TRUE);
331
332         offset += 4;
333
334         proto_tree_add_item(
335                 ntlmv2_tree, hf_ntlmv2_response_reserved, tvb,
336                 offset, 4, TRUE);
337
338         offset += 4;
339
340         offset = dissect_smb_64bit_time(
341                 tvb, ntlmv2_tree, offset, hf_ntlmv2_response_time);
342
343         proto_tree_add_item(
344                 ntlmv2_tree, hf_ntlmv2_response_chal, tvb,
345                 offset, 8, TRUE);
346
347         offset += 8;
348
349         proto_tree_add_item(
350                 ntlmv2_tree, hf_ntlmv2_response_unknown, tvb,
351                 offset, 4, TRUE);
352
353         offset += 4;
354
355         /* Variable length list of names */
356
357         while(1) {
358                 guint16 name_type = tvb_get_letohs(tvb, offset);
359                 guint16 name_len = tvb_get_letohs(tvb, offset + 2);
360                 proto_tree *name_tree = NULL;
361                 proto_item *name_item = NULL;
362                 char *name = NULL;
363
364                 if (ntlmv2_tree) {
365                         name_item = proto_tree_add_item(
366                                 ntlmv2_tree, hf_ntlmv2_response_name, 
367                                 tvb, offset, 0, TRUE);
368                         name_tree = proto_item_add_subtree(
369                                 name_item, ett_ntlmv2_response_name);
370                 }
371
372                 /* Dissect name header */
373
374                 proto_tree_add_item(
375                         name_tree, hf_ntlmv2_response_name_type, tvb,
376                         offset, 2, TRUE);
377
378                 offset += 2;
379
380                 proto_tree_add_item(
381                         name_tree, hf_ntlmv2_response_name_len, tvb,
382                         offset, 2, TRUE);
383
384                 offset += 2;
385
386                 /* Dissect name */
387
388                 if (name_len > 0) {
389                         name = tvb_fake_unicode(
390                                 tvb, offset, name_len / 2, TRUE);
391
392                         proto_tree_add_text(
393                                 name_tree, tvb, offset, name_len, 
394                                 "Name: %s", name);
395                 } else
396                         name = g_strdup("NULL");
397
398                 if (name_type == 0)
399                         proto_item_append_text(
400                                 name_item, "%s", 
401                                 val_to_str(name_type, ntlm_name_types,
402                                            "Unknown"));
403                 else
404                         proto_item_append_text(
405                                 name_item, "%s, %s",
406                                 val_to_str(name_type, ntlm_name_types,
407                                            "Unknown"), name);
408
409                 g_free(name);
410
411                 offset += name_len;
412
413                 proto_item_set_len(name_item, name_len + 4);
414
415                 if (name_type == 0) /* End of list */
416                         break;
417         };
418
419         return offset;
420 }
421
422 void register_smb_common(int proto_smb)
423 {
424         static hf_register_info hf[] = {
425
426                 { &hf_ntlmv2_response,
427                   { "NTLMv2 Response", "smb.ntlmv2response", FT_BYTES, 
428                     BASE_HEX, NULL, 0x0, "", HFILL }},
429
430                 { &hf_ntlmv2_response_hmac,
431                   { "HMAC", "smb.ntlmv2response.hmac", FT_BYTES, BASE_HEX, 
432                     NULL, 0x0, "", HFILL }},
433
434                 { &hf_ntlmv2_response_header,
435                   { "Header", "smb.ntlmv2response.header", FT_UINT32, 
436                     BASE_HEX, NULL, 0x0, "", HFILL }},
437
438                 { &hf_ntlmv2_response_reserved,
439                   { "Reserved", "smb.ntlmv2response.reserved", FT_UINT32, 
440                     BASE_HEX, NULL, 0x0, "", HFILL }},
441
442                 { &hf_ntlmv2_response_time,
443                   { "Time", "smb.ntlmv2response.time", FT_ABSOLUTE_TIME, 
444                     BASE_NONE, NULL, 0, "", HFILL }},
445
446                 { &hf_ntlmv2_response_chal,
447                   { "Client challenge", "smb.ntlmv2response.chal", FT_BYTES, 
448                     BASE_HEX, NULL, 0x0, "", HFILL }},
449
450                 { &hf_ntlmv2_response_unknown,
451                   { "Unknown", "smb.ntlmv2response.unknown", FT_UINT32, 
452                     BASE_HEX, NULL, 0x0, "", HFILL }},
453
454                 { &hf_ntlmv2_response_name,
455                   { "Name", "smb.ntlmv2response.name", FT_STRING, BASE_NONE, 
456                     NULL, 0x0, "", HFILL }},
457
458                 { &hf_ntlmv2_response_name_type,
459                   { "Name type", "smb.ntlmv2response.name.type", FT_UINT32, 
460                     BASE_DEC, VALS(ntlm_name_types), 0x0, "", HFILL }},
461
462                 { &hf_ntlmv2_response_name_len,
463                   { "Name len", "smb.ntlmv2response.name.len", FT_UINT32, 
464                     BASE_DEC, NULL, 0x0, "", HFILL }}
465         };
466
467         static gint *ett[] = {
468                 &ett_ntlmv2_response,
469                 &ett_ntlmv2_response_name
470         };
471
472         proto_register_subtree_array(ett, array_length(ett));
473         proto_register_field_array(proto_smb, hf, array_length(hf));
474 }