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