Add an extra argument to get_ms_string() so we can optionally pass
[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.15 2003/04/03 02:22:30 tpot 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         int len;
56
57         /* display a string from the tree and return the new offset */
58
59         len = tvb_strnlen(tvb, offset, -1);
60         if (len == -1) {
61                 /*
62                  * XXX - throw an exception?
63                  */
64                 len = tvb_length_remaining(tvb, offset);
65         }
66         str = g_malloc(len+1);
67         tvb_memcpy(tvb, (guint8 *)str, offset, len);
68         str[len] = '\0';
69
70         proto_tree_add_string(tree, hf_index, tvb, offset, len+1, str);
71
72         /* Return a copy of the string if requested */
73
74         if (data)
75                 *data = str;
76         else
77                 g_free(str);
78
79         return  offset+len+1;
80 }
81
82
83 int display_unicode_string(tvbuff_t *tvb, proto_tree *tree, int offset, int hf_index)
84 {
85         char *str, *p;
86         int len;
87         int charoffset;
88         guint16 character;
89
90         /* display a unicode string from the tree and return new offset */
91
92         /*
93          * Get the length of the string.
94          * XXX - is it a bug or a feature that this will throw an exception
95          * if we don't find the '\0'?  I think it's a feature.
96          */
97         len = 0;
98         while ((character = tvb_get_letohs(tvb, offset + len)) != '\0')
99                 len += 2;
100         len += 2;       /* count the '\0' too */
101
102         /*
103          * Allocate a buffer for the string; "len" is the length in
104          * bytes, not the length in characters.
105          */
106         str = g_malloc(len/2);
107
108         /*
109          * XXX - this assumes the string is just ISO 8859-1; we need
110          * to better handle multiple character sets in Ethereal,
111          * including Unicode/ISO 10646, and multiple encodings of
112          * that character set (UCS-2, UTF-8, etc.).
113          */
114         charoffset = offset;
115         p = str;
116         while ((character = tvb_get_letohs(tvb, charoffset)) != '\0') {
117                 *p++ = character;
118                 charoffset += 2;
119         }
120         *p = '\0';
121
122         proto_tree_add_string(tree, hf_index, tvb, offset, len, str);
123
124         g_free(str);
125
126         return  offset+len;
127 }
128
129 /* Max string length for displaying Unicode strings.  */
130 #define MAX_UNICODE_STR_LEN     256
131
132 /* Turn a little-endian Unicode '\0'-terminated string into a string we
133    can display.
134    XXX - for now, we just handle the ISO 8859-1 characters.
135    If exactlen==TRUE then us_lenp contains the exact len of the string in
136    bytes. It might not be null terminated !
137    bc specifies the number of bytes in the byte parameters; Windows 2000,
138    at least, appears, in some cases, to put only 1 byte of 0 at the end
139    of a Unicode string if the byte count
140 */
141 static gchar *
142 unicode_to_str(tvbuff_t *tvb, int offset, int *us_lenp, gboolean exactlen,
143                    guint16 bc)
144 {
145   static gchar  str[3][MAX_UNICODE_STR_LEN+3+1];
146   static gchar *cur;
147   gchar        *p;
148   guint16       uchar;
149   int           len;
150   int           us_len;
151   int           overflow = 0;
152
153   if (cur == &str[0][0]) {
154     cur = &str[1][0];
155   } else if (cur == &str[1][0]) {
156     cur = &str[2][0];
157   } else {
158     cur = &str[0][0];
159   }
160   p = cur;
161   len = MAX_UNICODE_STR_LEN;
162   us_len = 0;
163   for (;;) {
164     if (bc == 0)
165       break;
166     if (bc == 1) {
167       /* XXX - explain this */
168       if (!exactlen)
169         us_len += 1;    /* this is a one-byte null terminator */
170       break;
171     }
172     uchar = tvb_get_letohs(tvb, offset);
173     if (uchar == 0) {
174       us_len += 2;      /* this is a two-byte null terminator */
175       break;
176     }
177     if (len > 0) {
178       if ((uchar & 0xFF00) == 0)
179         *p++ = uchar;   /* ISO 8859-1 */
180       else
181         *p++ = '?';     /* not 8859-1 */
182       len--;
183     } else
184       overflow = 1;
185     offset += 2;
186     bc -= 2;
187     us_len += 2;
188     if(exactlen){
189       if(us_len>= *us_lenp){
190         break;
191       }
192     }
193   }
194   if (overflow) {
195     /* Note that we're not showing the full string.  */
196     *p++ = '.';
197     *p++ = '.';
198     *p++ = '.';
199   }
200   *p = '\0';
201   *us_lenp = us_len;
202   return cur;
203 }
204
205 /* nopad == TRUE : Do not add any padding before this string
206  * exactlen == TRUE : len contains the exact len of the string in bytes.
207  * bc: pointer to variable with amount of data left in the byte parameters
208  *   region
209  */
210 const gchar *
211 get_unicode_or_ascii_string(tvbuff_t *tvb, int *offsetp,
212     gboolean useunicode, int *len, gboolean nopad, gboolean exactlen,
213     guint16 *bcp)
214 {
215   static gchar  str[3][MAX_UNICODE_STR_LEN+3+1];
216   static gchar *cur;
217   const gchar *string;
218   int string_len;
219   unsigned int copylen;
220
221   if (*bcp == 0) {
222     /* Not enough data in buffer */
223     return NULL;
224   }
225   if (useunicode) {
226     if ((!nopad) && (*offsetp % 2)) {
227       /*
228        * XXX - this should be an offset relative to the beginning of the SMB,
229        * not an offset relative to the beginning of the frame; if the stuff
230        * before the SMB has an odd number of bytes, an offset relative to
231        * the beginning of the frame will give the wrong answer.
232        */
233       (*offsetp)++;   /* Looks like a pad byte there sometimes */
234       (*bcp)--;
235       if (*bcp == 0) {
236         /* Not enough data in buffer */
237         return NULL;
238       }
239     }
240     if(exactlen){
241       string_len = *len;
242     }
243     string = unicode_to_str(tvb, *offsetp, &string_len, exactlen, *bcp);
244   } else {
245     if(exactlen){
246       /*
247        * The string we return must be null-terminated.
248        */
249       if (cur == &str[0][0]) {
250         cur = &str[1][0];
251       } else if (cur == &str[1][0]) {
252         cur = &str[2][0];
253       } else {
254         cur = &str[0][0];
255       }
256       copylen = *len;
257       if (copylen > MAX_UNICODE_STR_LEN)
258         copylen = MAX_UNICODE_STR_LEN;
259       tvb_memcpy(tvb, (guint8 *)cur, *offsetp, copylen);
260       cur[copylen] = '\0';
261       if (copylen > MAX_UNICODE_STR_LEN)
262         strcat(cur, "...");
263       string_len = *len;
264       string = cur;
265     } else {
266       string_len = tvb_strsize(tvb, *offsetp);
267       string = tvb_get_ptr(tvb, *offsetp, string_len);
268     }
269   }
270   *len = string_len;
271   return string;
272 }
273
274 int
275 dissect_smb_unknown(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset)
276 {
277         /* display data as unknown */
278
279         proto_tree_add_text(tree, tvb, offset, -1, "Data (%u bytes)",
280             tvb_reported_length_remaining(tvb, offset));
281
282         return offset+tvb_length_remaining(tvb, offset);
283 }