Remove all $Id$ from top of file
[metze/wireshark/wip.git] / epan / dissectors / 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  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * Copied from packet-pop.c
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include "config.h"
27
28 #include <glib.h>
29
30 #include <epan/packet.h>
31 #include <epan/wmem/wmem.h>
32 #include <epan/strutil.h>
33 #include "packet-smb-common.h"
34
35 #include "packet-dns.h"
36
37 /*
38  * Share type values - used in LANMAN and in SRVSVC.
39  *
40  * XXX - should we dissect share type values, at least in SRVSVC, as
41  * a subtree with bitfields, as the 0x80000000 bit appears to be a
42  * hidden bit, with some number of bits at the bottom being the share
43  * type?
44  *
45  * Does LANMAN use that bit?
46  */
47 const value_string share_type_vals[] = {
48         {0, "Directory tree"},
49         {1, "Printer queue"},
50         {2, "Communications device"},
51         {3, "IPC"},
52         {0x80000000, "Hidden Directory tree"},
53         {0x80000001, "Hidden Printer queue"},
54         {0x80000002, "Hidden Communications device"},
55         {0x80000003, "Hidden IPC"},
56         {0, NULL}
57 };
58
59 int display_ms_string(tvbuff_t *tvb, proto_tree *tree, int offset, int hf_index, char **data)
60 {
61         char *str;
62         gint len;
63
64         /* display a string from the tree and return the new offset */
65
66         str = tvb_get_stringz(wmem_packet_scope(), tvb, offset, &len);
67         proto_tree_add_string(tree, hf_index, tvb, offset, len, str);
68
69         /* Return a copy of the string if requested */
70
71         if (data)
72                 *data = str;
73
74         return  offset+len;
75 }
76
77
78 int display_unicode_string(tvbuff_t *tvb, proto_tree *tree, int offset, int hf_index, char **data)
79 {
80         char *str, *p;
81         int len;
82         int charoffset;
83         guint16 character;
84
85         /* display a unicode string from the tree and return new offset */
86
87         /*
88          * Get the length of the string.
89          * XXX - is it a bug or a feature that this will throw an exception
90          * if we don't find the '\0'?  I think it's a feature.
91          */
92         len = 0;
93         while (tvb_get_letohs(tvb, offset + len) != '\0')
94                 len += 2;
95         len += 2;       /* count the '\0' too */
96
97         /*
98          * Allocate a buffer for the string; "len" is the length in
99          * bytes, not the length in characters.
100          */
101         str = (char *)wmem_alloc(wmem_packet_scope(), len/2);
102
103         /*
104          * XXX - this assumes the string is just ISO 8859-1; we need
105          * to better handle multiple character sets in Wireshark,
106          * including Unicode/ISO 10646, and multiple encodings of
107          * that character set (UCS-2, UTF-8, etc.).
108          */
109         charoffset = offset;
110         p = str;
111         while ((character = tvb_get_letohs(tvb, charoffset)) != '\0') {
112                 *p++ = (char) character;
113                 charoffset += 2;
114         }
115         *p = '\0';
116
117         proto_tree_add_string(tree, hf_index, tvb, offset, len, str);
118
119         if (data)
120                 *data = str;
121
122         return  offset+len;
123 }
124
125 /* Max string length for displaying Unicode strings.  */
126 #define MAX_UNICODE_STR_LEN     256
127
128 int dissect_ms_compressed_string(tvbuff_t *tvb, proto_tree *tree, int offset, int hf_index,
129                                  const char **data)
130 {
131         int compr_len;
132         const guchar *str = NULL;
133
134         /* The name data MUST start at offset 0 of the tvb */
135         compr_len = expand_dns_name(tvb, offset, MAX_UNICODE_STR_LEN+3+1, 0, &str);
136         proto_tree_add_string(tree, hf_index, tvb, offset, compr_len, str);
137
138         if (data)
139                 *data = str;
140
141         return offset + compr_len;
142 }
143
144 /* Turn a little-endian Unicode '\0'-terminated string into a string we
145    can display.
146    XXX - for now, we just handle the ISO 8859-1 characters.
147    If exactlen==TRUE then us_lenp contains the exact len of the string in
148    bytes. It might not be null terminated !
149    bc specifies the number of bytes in the byte parameters; Windows 2000,
150    at least, appears, in some cases, to put only 1 byte of 0 at the end
151    of a Unicode string if the byte count
152 */
153 static gchar *
154 unicode_to_str(tvbuff_t *tvb, int offset, int *us_lenp, gboolean exactlen,
155                guint16 bc)
156 {
157         gchar *cur;
158         gchar        *p;
159         guint16       uchar;
160         int           len;
161         int           us_len;
162         gboolean      overflow = FALSE;
163
164         cur=(gchar *)wmem_alloc(wmem_packet_scope(), MAX_UNICODE_STR_LEN+3+1);
165         p = cur;
166         len = MAX_UNICODE_STR_LEN;
167         us_len = 0;
168         for (;;) {
169                 if (bc == 0)
170                         break;
171
172                 if (bc == 1) {
173                         /* XXX - explain this */
174                         if (!exactlen)
175                                 us_len += 1;    /* this is a one-byte null terminator */
176                         break;
177                 }
178
179                 uchar = tvb_get_letohs(tvb, offset);
180                 if (uchar == 0) {
181                         us_len += 2;    /* this is a two-byte null terminator */
182                         break;
183                 }
184
185                 if (len > 0) {
186                         if ((uchar & 0xFF00) == 0)
187                                 *p++ = (gchar) uchar;   /* ISO 8859-1 */
188                         else
189                                 *p++ = '?';     /* not 8859-1 */
190                         len--;
191                 } else
192                         overflow = TRUE;
193
194                 offset += 2;
195                 bc -= 2;
196                 us_len += 2;
197
198                 if(exactlen){
199                         if(us_len>= *us_lenp){
200                                 break;
201                         }
202                 }
203         }
204         if (overflow) {
205                 /* Note that we're not showing the full string.  */
206                 *p++ = '.';
207                 *p++ = '.';
208                 *p++ = '.';
209         }
210
211         *p = '\0';
212         *us_lenp = us_len;
213
214         return cur;
215 }
216
217 /* nopad == TRUE : Do not add any padding before this string
218  * exactlen == TRUE : len contains the exact len of the string in bytes.
219  * bc: pointer to variable with amount of data left in the byte parameters
220  *   region
221  */
222 const gchar *
223 get_unicode_or_ascii_string(tvbuff_t *tvb, int *offsetp,
224                             gboolean useunicode, int *len, gboolean nopad, gboolean exactlen,
225                             guint16 *bcp)
226 {
227         gchar *cur;
228         const gchar *string;
229         int string_len = 0;
230         int copylen;
231         gboolean overflow = FALSE;
232
233         if (*bcp == 0) {
234                 /* Not enough data in buffer */
235                 return NULL;
236         }
237
238         if (useunicode) {
239                 if ((!nopad) && (*offsetp % 2)) {
240                         (*offsetp)++;   /* Looks like a pad byte there sometimes */
241                         (*bcp)--;
242
243                         if (*bcp == 0) {
244                                 /* Not enough data in buffer */
245                                 return NULL;
246                         }
247                 }
248
249                 if(exactlen){
250                         string_len = *len;
251                         if (string_len < 0) {
252                                 /* This probably means it's a very large unsigned number; just set
253                                    it to the largest signed number, so that we throw the appropriate
254                                    exception. */
255                                 string_len = INT_MAX;
256                         }
257                 }
258
259                 string = unicode_to_str(tvb, *offsetp, &string_len, exactlen, *bcp);
260
261         } else {
262                 if(exactlen){
263                         /*
264                          * The string we return must be null-terminated.
265                          */
266                         cur=(gchar *)wmem_alloc(wmem_packet_scope(), MAX_UNICODE_STR_LEN+3+1);
267                         copylen = *len;
268
269                         if (copylen < 0) {
270                                 /* This probably means it's a very large unsigned number; just set
271                                    it to the largest signed number, so that we throw the appropriate
272                                    exception. */
273                                 copylen = INT_MAX;
274                         }
275
276                         tvb_ensure_bytes_exist(tvb, *offsetp, copylen);
277
278                         if (copylen > MAX_UNICODE_STR_LEN) {
279                                 copylen = MAX_UNICODE_STR_LEN;
280                                 overflow = TRUE;
281                         }
282
283                         tvb_memcpy(tvb, (guint8 *)cur, *offsetp, copylen);
284                         cur[copylen] = '\0';
285
286                         if (overflow)
287                                 g_strlcat(cur, "...",MAX_UNICODE_STR_LEN+3+1);
288
289                         string_len = *len;
290                         string = cur;
291                 } else {
292                         string = tvb_get_const_stringz(tvb, *offsetp, &string_len);
293                 }
294         }
295
296         *len = string_len;
297         return string;
298 }